Byte Pair Encoding(BPE)の仕組みと多言語対応

2026年10月28日公開

Byte Pair Encoding(BPE)の仕組みと多言語対応

大規模言語モデル(LLM)に同じ内容を入力しても、言語によって必要なトークン数は変わります。トークン数が多ければ、文脈長の上限に収まる原文が短くなり、生成にも多くのステップが必要です。トークナイザーが文章をどこで区切るかによって、必要なトークン数が変わります。
Byte Pair Encoding(BPE)は、学習テキストで頻出する隣接ペアを順に結合し、可変長のトークンを作る方式です。語彙の学習では頻度を使い、学習後の分割では固定した結合規則の優先順位を使います。頻出する綴りを長いトークンにまとめるため、学習データの言語構成が、各言語を何トークンで表せるかに影響します。
BPEは1994年に圧縮方式として提案され[1]、Sennrichらが2016年に、ニューラル機械翻訳で単語をより小さい単位へ分割する方法として応用しました[2]。GPT-2では、文字をUTF-8のバイト列に変換してから扱うバイト単位のBPEが採用されています[3]。本記事では、小さな例で学習と分割を追い、バイト表現、多言語の語彙配分、既存モデルへの語彙追加を説明します。

1. 頻出ペアからの語彙学習

トークナイザーは、テキストをモデルが扱う単位(トークン)に分け、それぞれに割り当てられた整数のIDへ変換します。語彙は、そのトークナイザーで使えるトークンの集合です。単語全体を1トークンで表すことも、単語を複数のトークンに分けることもできます。LLMの学習では、このID列を使い、文脈に続く次のIDを予測するようにモデルの重みを更新します。
BPEでは、まず文字などの小さな単位を初期語彙に登録し、学習テキストをその単位に分けます。そこから、次の手順で長いトークンを作ります。
  1. 隣接する2トークンの組(ペア)を数え、最も頻度の高いペアを選びます。
  2. 2つを連結したトークンを語彙に加え、学習データ中のそのペアを左から重ならないように置き換えます。
  3. 結合規則と選んだ順番を保存し、置き換え後の列でペアの頻度を数え直します。
指定した語彙数に達するか、結合できるペアがなくなるまで、この操作を繰り返します。途中で作ったトークンも語彙に残るため、長い単語だけでなく、その一部も表現できます。

1.1. 4種類の単語からの語彙学習

lowが5回、lowerが2回、newestが6回、widestが3回現れるデータで、4回の結合を追います。文字(Unicodeコードポイント)から始め、単語の中だけで結合します。同頻度のペアは、トークンIDの組の辞書順で選びます。

初期文字を文字コード順のd, e, i, l, n, o, r, s, t, wに並べ、IDを0〜9とします。結合で作ったトークンには10以降のIDを順に割り当てます。同頻度のペアは、左側のIDが小さい方を、左側も同じなら右側のIDが小さい方を選びます。

例えばe + sはIDの組が(1, 7)、s + tは(7, 8)なので、前者を先に結合します。この例では語末記号も付けていません。Sennrichらの原著とは、語末記号の有無と同頻度の扱いが異なります[2]。

  1. [2] Rico Sennrich, Barry Haddow, Alexandra Birch, "Neural Machine Translation of Rare Words with Subword Units," ACL, 2016.
最初に最も多いペアはe + sとs + tです。どちらもnewestとwidestに1回ずつ含まれ、学習データ全体では合計9回現れます。同頻度のときの規則に従ってe + s → esを選ぶと、両単語の末尾はes | tになります。|はトークンの区切りです。数え直すとes + tが9回で最も多く、次の結合でestができます。
続いて、lowとlowerに共通するl + o、lo + wを結合します。表の順位(rank)は、規則を学習した順番を0から数えた値です。頻度は各結合の直前に数えた出現回数で、結合後のIDは新しいトークンに付けた番号を表します。
順位結合規則頻度結合後のID
0e + s → es910
1es + t → est911
2l + o → lo712
3lo + w → low713
4回の結合により、lowは1トークン、lowerはlow | e | rの3トークンになります。newestとwidestでは、末尾のestが1トークンにまとまりました。語彙数は、初期文字10種類に4トークンを加えた14です。この例のestは英語の接尾辞と一致しますが、BPEの選択基準は出現頻度です。

1.2. ペアの頻度とトークン数の削減

2トークンを1つに結合するたびに、列は1トークン短くなります。頻出ペアを選ぶと、多くの位置でこの短縮を行えます。結合のたびに隣接関係とペアの頻度は変わります。BPEは、その時点で最も頻度の高いペアを選ぶ貪欲法で語彙を増やします。

ペアの頻度を数える際は、重なる位置も含めます。例えばaaaのa + aは2か所と数えますが、実際に結合できるのは1組です。頻度と、結合で減るトークン数には、このような違いがあります。

各トークン列\(s\)の出現回数を\(f(s)\)とすると、ペア\((a,b)\)の頻度は次のように書けます。\(|s|\)は現在の列の長さ、\(s_i\)は\(i\)番目のトークン、\(\mathbf{1}\)は条件が成り立つときに1、それ以外で0を取る指示関数です。

\[ C(a,b)=\sum_s f(s)\sum_{i=1}^{|s|-1} \mathbf{1}[(s_i,s_{i+1})=(a,b)]. \]

内側の和は隣接位置を数え、外側の和は各列の出現回数を掛けて合計します。例えば§1.1のlowは5回現れるので、初回の集計ではl + oとo + wの頻度にそれぞれ5を加えます。学習では\(C(a,b)\)が最大のペアを選び、各列で左から重ならないように置き換えます。

2. 学習済みの規則による分割

学習後は、入力を初期単位に分け、保存した規則を適用してトークンの区切りを決めます。現在の列で結合できるペアのうち、順位が最も小さいものを選び、適用できる規則がなくなるまで繰り返します。
学習データになかったlowestを、§1.1の4規則で分割してみます。初期状態のl | o | w | e | s | tには、順位0のe + sと順位2のl + oがあります。先にesを作ると、順位1のes + tが結合できるようになります。その後でlo、lowを作り、最終的な分割はlow | estです。学習時に単語全体が現れなくても、既存のトークンを組み合わせて表せます。
lowestをl、o、w、e、s、tに分け、順位0でes、順位1でest、順位2でlo、順位3でlowを作り、lowとestの2トークンを得る過程。最終IDは13と11。
図1:固定した結合順位によるlowestの分割 初期単位を文字とし、4つの結合規則を使う例です。オレンジ色は、その段階で結合したトークンを示します。最下段のIDは、結合した順ではなく入力中の位置の順に並びます。
得られたID列は、原文の順に並ぶ[13, 11]です。結合順位は規則を適用する優先度、トークンIDはモデルへ渡すトークンの識別番号を表します。実装によっては同じ数値を兼用しますが、役割は異なります。
BPEは結合順位に従うため、入力の中央から結合することもあります。例えばb + c、a + b、c + dの3規則をこの順に優先するなら、abcdの分割はa | bc | dです。同じ語彙を左から最長一致で探すとab | cdなので、分割結果もトークン数も異なります。

2.1. Pythonでの実装

結合順位による分割をPythonで実装すると、次のようになります。rulesのキーは隣接するIDの組、値は(順位, 結合後のID)です。encode_idsは毎回すべての隣接ペアを調べ、適用できる規則のうち順位が最も小さいものを1か所で使います。
def encode_ids(initial_ids, rules):
    sequence = list(initial_ids)
    while len(sequence) >= 2:
        candidates = [
            (rules[pair][0], i, rules[pair][1])
            for i, pair in enumerate(zip(sequence, sequence[1:]))
            if pair in rules
        ]
        if not candidates:
            break
        # 順位が最小の候補を選び、同順位なら左側を優先します。
        _, i, output = min(candidates)
        sequence[i:i + 2] = [output]
    return sequence

# 初期文字にID 0〜9を割り当てます。
alphabet = {char: i for i, char in enumerate("deilnorstw")}
rules = {
    (1, 7): (0, 10),   # e  + s → es
    (10, 8): (1, 11),  # es + t → est
    (3, 5): (2, 12),   # l  + o → lo
    (12, 9): (3, 13),  # lo + w → low
}
initial_ids = [alphabet[char] for char in "lowest"]
print(encode_ids(initial_ids, rules))  # [13, 11] = low | est
この関数は初期ID列を受け取るので、バイト単位のIDと規則を用意すれば、バイト単位のBPEにも使えます。学習と復号を含む実装は、実行用コードとデータに収録しています。Pythonの標準ライブラリーだけで動き、実行方法は§4.2の補足にあります。
このコードは結合のたびに候補を調べ直すため、長い入力ほど探索に時間がかかります。結合した位置の左右だけを更新し、順位の小さい候補を取り出す優先度キューを使えば、分割の計算量を減らせます。

初期トークン数を\(n\)、結合回数を\(m\)とし、IDペアの照合を定数時間とします。このコードは、候補の走査と配列の置き換えに1回あたり最大\(O(n)\)かかるため、初回の走査を含む全体の計算量は\(O(n+mn)\)です。\(m\)は最大で\(n-1\)なので、最悪計算量は\(O(n^2)\)になります。

隣接関係を管理するデータ構造と優先度キューを組み合わせれば、結合した位置の左右だけを更新できます。同じ仮定の下で、候補の取り出しと追加は1回あたり\(O(\log n)\)、分割全体では\(O(n\log n)\)です。

短い入力では、データ構造を管理する負担が小さい配列の走査が速いこともあります。tiktoken 0.12.0の実装も配列を使い、短い入力でのキャッシュ効率を採用理由として挙げています[16]。実行速度を比べる際は、事前分割後の各断片の長さも確認します。

  1. [16] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.

3. 文字・バイト・前処理の関係

3.1. バイト単位のBPEと未知の文字

§2のlowestを分割できたのは、使われている文字がすべて初期語彙に含まれていたためです。文字を初期単位にする方式では、語彙にない文字への対応も必要になります。バイト単位のBPEは、テキストをUTF-8のバイト列に変換し、0〜255の256種類のバイト値から結合を始めます。全種類を初期語彙に含めれば、学習データになかった文字も、そのバイト列で表せます。
UTF-8では、ASCII文字のAは1バイト、猫は3バイト、🙂は4バイトで表されます[4]。BPEはこのバイト列の隣接ペアを結合するため、1トークンが1文字の途中で終わることも、複数の文字を含むこともあります。
猫を表す3バイトも、必要な結合を学習すれば1トークンにまとまります。各言語をどれだけ短く表せるかは、どのバイトの並びの結合を学んだかによって変わります。
A猫🙂のコードポイントとUTF-8の8バイト。Aは41、猫はE7 8C AB、絵文字はF0 9F 99 82。説明用のトークンは41、E7 8C、AB、F0 9F 99 82の4組に分かれ、猫の内部に境界がある。
図2:文字の境界とトークンの境界 「A猫🙂」を、上段は3コードポイント、中央はUTF-8の8バイト、下段は4トークンとして示しています。下段は、猫の3バイトを途中で区切る説明用の分割例です。バイト値は16進数で表しています。
ID列をテキストへ戻す復号では、各IDに対応するバイト列をすべて連結してからUTF-8として解釈します。図2のE7 8Cは、単独では完全な文字を表せませんが、次のABと連結すれば猫に戻ります。個々のトークンを先に文字列へ変換すると、不完全なバイト列が置換文字に変わり、原文を復元できなくなることがあります。
文字を初期単位にして語彙を学習する場合には、byte fallbackという方法で未知の文字に対応できます。入力に語彙にない文字が現れたら、その文字をUTF-8のバイト列に変換し、1バイトずつトークンにします。

SentencePieceでbyte fallbackを使うには、byte_fallbackを有効にします[17]。指定した語彙数のうち256枠をバイト用に使うため、文字や文字列に使える枠はその分だけ減ります。

SentencePieceは、BPEやUnigram(§8.1)を選べるライブラリーです[18]。分割のアルゴリズムとbyte fallbackの有無は、別の設定として指定します。

  1. [17] Google, "SentencePiece Training Options," SentencePiece Documentation, 2026.
  2. [18] Taku Kudo, John Richardson, "SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing," EMNLP System Demonstrations, 2018.

3.2. 正規化と事前分割

実際のトークナイザーが返すID列には、BPE以外の処理も影響します。例えばHugging Face Tokenizersでは、表記を揃える正規化、結合できる範囲を区切る事前分割、BPEなどによる分割、特殊トークンの追加といった後処理を組み合わせます[5]。
正規化は、一定の規則で表記を揃える処理です。例えば、アクセント付きのéには、1コードポイントの表現と、eに結合アクセントを続ける2コードポイントの表現があります。UnicodeのNFCは両者を同じコードポイント列に変換し、NFKCはさらに全角のAをAにするような変換も行います[6]。表記を揃えると頻度をまとめて数えられますが、変換前の表記の区別は失われるため、復号して戻せるのは正規化後のテキストです。
事前分割(pre-tokenization)では、BPEを適用する範囲をあらかじめ区切ります。例えばhello worldをhelloと、先頭に空白を含む worldに分ければ、その境界をまたぐ結合は学習時にも分割時にも行いません。語彙数を増やしても、この設定のままではhello world全体を1トークンにはできません。
GPT-2では、文字・数字・記号などの区分で事前分割し、その範囲内にバイト単位のBPEを適用します[3]。区切り方の影響は言語によって異なります。空白を境界にするだけでも、通常は単語間に空白を入れる英語と、入れない日本語では、結合の対象となる範囲が変わります。
文章の開始・終了などを示す特殊トークンには、通常の文字列とは別の扱いが定められています。原文の復元が必要な用途では、正規化や空白処理に加え、特殊トークンを表す文字列を入力した場合の動作も確かめます。ライブラリーごとの設定を確認し、変換後のID列を復号して原文と比較すれば、その入力を欠落や変化なく戻せるかを検証できます。
実装分割の構成確認する設定
tiktoken[16]バイト列の順位表と、事前分割に使う正規表現設定名(encoding)、特殊トークン、順位とIDの対応
SentencePiece[17]BPEやUnigramを選択し、モデルに正規化なども保存文字の採用範囲、byte fallback、正規化、空白処理
Hugging Face Tokenizers[5]正規化、事前分割、BPEなどの分割モデル、デコーダーの組み合わせ各部品の設定と、追加トークンの照合方法

SentencePieceの既定の正規化は、独自のNFKC系の規則です。identityで文字の正規化を無効にしても、空白処理には別の設定があります[19]。例えば、先頭への空白追加や連続する空白の削除も、原文との一致に影響します。

  1. [16] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.
  2. [17] Google, "SentencePiece Training Options," SentencePiece Documentation, 2026.
  3. [5] Hugging Face, "The tokenization pipeline," Tokenizers Documentation, 2026.
  4. [19] Google, "Text Normalization in SentencePiece," SentencePiece Documentation, 2026.

4. 多言語で生じる分割長の差

4.1. 学習データの比率と表記の共有

通常のBPEは、多言語のデータを混ぜても言語を区別せず、ペアの出現回数を合計します。データ量の多い言語で頻出するペアは合計でも上位に入りやすく、その言語の綴りをまとめるトークンが優先して作られます。言語ごとの重み付けでは、各言語で数えた頻度に係数を掛け、集計への寄与を調整します。

言語\(\ell\)でのペア\((a,b)\)の出現回数を\(C_\ell(a,b)\)、その言語の学習時の重みを\(w_\ell\)とすると、選択に使う頻度は次の形です。

\[ C(a,b)=\sum_\ell w_\ell C_\ell(a,b). \]

例えば\(w_\ell=2\)なら、その言語の各ペアを2倍の回数で数えます。これは、その言語の学習文を2回ずつ含める場合と同じ集計です。重みを変えずに学習する間も、結合が進むたびに\(C_\ell(a,b)\)は変わります。

学習データ量に加えて、言語間で共有される綴りも結合の選択に影響します。複数の言語で使う同じ綴りは頻度が合算され、作られたトークンも共有されます。文字体系や語形変化が異なれば、頻出する綴りも変わります。空白の使い方と事前分割による制約もあるため、学習データ量を揃えるだけでは分割長は揃いません。

4.2. 学習比率を変えた小規模実験

5言語の自作文を使い、語彙数512のバイト単位のBPEで小規模な実験をしました。学習時の言語比率だけを変えた3条件で、同じ評価文を何トークンに分けるかを比較します。

学習用には各言語16文、評価用には別の8文を使っています。文ごとにおおむね同じ内容を表す自作文で、専門家による翻訳確認を経た評価データではありません。

言語\(\ell\)の学習文の合計UTF-8バイト数を\(B_\ell\)、下表の目標比率を\(p_\ell\)として、その言語の各文に\(100000p_\ell/B_\ell\)の重みを付けます。\(p_\ell\)の合計は1で、全条件の重み付きバイト量は100,000です。PythonのFractionで厳密に計算し、無作為抽出は行いません。英語50%の条件は、80%の条件の各比率の平方根を取り、合計が1になるように正規化したものです。

初期語彙は256種類のバイト値で、256回の結合を学びます。文字の正規化はせず、文をまたぐ結合を禁じ、文内の空白をまたぐ結合は許します。評価時には重みを掛けず、各言語8文のトークン数を合計します。

配布ZIPを展開し、展開先で次のコマンドを実行すると、テストの実行後に実験結果がresults/へ出力されます。入力データはdata/toy_parallel.json、表の値はresults/multilingual_metrics.csvで確認できます。

python3 code/run_all.py

code/bpe_core.pyはバイト単位の最小実装、code/minimal_bpe.pyは文字単位にも対応する実装です。

表は、各言語でおおむね同じ内容を表す自作評価文8文の合計トークン数です。左列の比率は、学習時の重み付きUTF-8バイト量を表します。同じ言語の列を縦に読むと、学習比率を変えた効果が分かります。
学習時のバイト量の比率(%)
英/日/中/アラビア/ヒンディー
英語日本語中国語アラビア語ヒンディー語
80/5/5/5/5137310266344452
50/12.5/12.5/12.5/12.5140259233229347
20/20/20/20/20184208177189259
英語80%から各言語20%へ変えると、日本語は310から208トークンに減り、英語は137から184トークンに増えました。語彙数と学習文を固定しても、言語ごとの頻度をどれだけ重く数えるかによって、語彙に入るトークンと分割長が変わります。

5. 分割長・計算コスト・モデル品質の評価

5.1. 分割長と言語間の差

複数のトークナイザーを比べるときは、同じ評価文のトークン数を数えます。言語間の差を見る場合は対訳文を使い、同じ内容を表すのに必要なトークン数を比べます。文章の分野や翻訳の書き方も結果に影響するため、使ったトークナイザーと評価データを明示します。
対訳集合で、言語\(\ell\)の合計トークン数を\(T_\ell\)、基準言語を\(r\)とすると、倍率は\(T_\ell/T_r\)です。§4.2で学習比率を英語80%から各言語20%へ変えると、日本語の英語に対する倍率は約2.26倍から約1.13倍へ縮まっています。これは日本語の短縮と英語の増加の両方による変化です。各言語のトークン数も併記すれば、倍率が変わった理由を確認できます。

5.2. 語彙数と計算コスト

分割後のトークン数が減ると、モデルが処理する系列が短くなります。入力列を一括処理する大域Attentionは、列内の各位置からほかの位置の情報を集めるため、系列長の2乗に比例する計算を含みます。1トークンずつ生成するモデルでは、同じ文章を出力するためのステップも減ります。
語彙を増やして分割を短くする場合は、モデルの入出力に使う行列が大きくなります。入力埋め込みはIDごとにベクトルを1本持つため、語彙数\(V\)、ベクトルの次元数\(d\)なら、パラメーター数は\(Vd\)です。例えば\(d=4096\)で語彙を50,000増やし、重みを1要素2バイトで保存すると、1行列あたり約410 MB増える計算になります。入力と出力で重みを共有しないモデルでは、出力行列にも同じ容量が加わります。

増えるパラメーター数は\(50000\times4096=204800000\)です。16ビットの浮動小数点形式BF16など、1要素2バイトで保存する場合、増加量は\(409600000\)バイト、10進のMBで409.6 MBになります。入力と出力の2行列を別々に持つ場合は、合計819.2 MBの増加です。

これは重みだけの計算値です。学習時には勾配やオプティマイザーの状態なども必要になり、実際のメモリー使用量は学習方法によって変わります。

出力行列を使って全語彙のスコアを求める計算も、語彙数とともに増えます。語彙の追加では、系列長の短縮で減る計算と、出力候補の増加で増える計算の両方が生じます。実際の処理時間とメモリー使用量は、利用するモデルと入力長で測ります。

5.3. モデル品質の比較

モデルの品質は、目的とする質問応答や翻訳などの成績で評価します。PathPieceの研究では、固定した語彙でトークン数が最小になる分割を使い、モデルの性能との関係を調べています。その実験では、トークン数が少なければ下流タスクの性能も高くなるという仮説を支持する結果は得られませんでした[7]。
次のトークンの予測を比べる場合は、同じ評価文を欠落なく表現できることを確認し、損失を測る単位を揃えます。未知の文字が共通の未知語トークンへ置き換わったり、前処理で情報が失われたりしていないかは、復号結果を原文と比較して確認できます。

1トークンあたりの損失は、トークナイザーによって1単位が表す量が変わるため、そのままでは比較できません。平均損失を指数関数で変換したperplexityにも、同じ問題があります。

比較には、同じ評価テキストに対する負の対数尤度をビット単位で合計し、UTF-8バイト数で割ったBits per Byte(BPB)を使えます。値が小さいほど、モデルが評価文のトークン列に高い確率を与えています。

モデルを学習して比べる場合は、学習に使う原文量・トークン数・演算量のどれを揃えるかも決めます。同じトークン数を学習していても、分割が短いほど多くの原文を読むことになるためです。

6. PA-BPEによる言語別の語彙配分

§4.2では、言語ごとの頻度に固定した重みを掛けました。ForoutanらのParity-aware BPE(PA-BPE、ACL 2026)[8]は、学習途中の分割長に応じて、次の結合で優先する言語を選び直します。対訳データを使う方式では、同じ内容を表すのに最も多くのトークンを使っている言語を優先します。
対訳の開発用データで言語を選ぶ方式では、所定の語彙数に達するまで、次の操作を繰り返します。
  1. 開発用データの1文あたりの平均トークン数を比べ、最も多い言語を選びます。
  2. その言語の学習データで、最も頻出する隣接ペアを選びます。
  3. 選んだペアを全言語の学習・開発用データで結合します。
対訳が必要なのは言語を選ぶための開発用データで、ペアの集計には言語別の学習データを使えます。学習後は全言語で共通の結合規則を使い、通常のBPEと同じ手順で入力を分割します。
対訳の開発データで平均トークン数が最大の言語を選び、その言語の学習データで最頻ペアを選択する。全言語の学習・開発データに結合を適用し、分割と統計を更新して、所定の語彙数まで繰り返す流れ。
図3:PA-BPEの語彙学習 対訳文の平均トークン数で言語を選び、その言語の学習データで結合規則を選ぶ方式です。矢印は1回の結合後に分割と統計を更新する流れを示します。原著§4の手順を図示しています[8]。
原著の30言語・語彙数128,000での比較では、FLORES+の対訳データ全体のトークン数をほぼ保ちながら、言語間の分割長の差を縮めています[8]。

語彙の学習には、言語ごとの量が不均衡な30言語のFineWeb2を使っています。原著のTable 1にある通常のBPEとPA-BPEの結果を抜き出すと、次のようになります[8]。

方式言語間の差(Gini係数)全体の圧縮率(文/トークン)
BPE0.0640.0275
PA-BPE0.0070.0276

Gini係数は、言語ごとのトークン数の差を測る指標で、0に近いほど差が小さくなります。圧縮率は文数を総トークン数で割った値で、大きいほど少ないトークンで表せています。

  1. [8] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026.
モデル品質の評価では、通常のBPEと、語彙学習の途中からPA-BPEへ切り替える派生方式を比べています。30億パラメーターのモデルを使った12種類の多言語ベンチマークでの比較について、著者らは、一貫した性能悪化を示す結果は見られなかったと報告しています[8]。

原著のTable 2は、通常のBPE、学習の前半を通常のBPE・後半をPA-BPEにする方式(hybrid)、さらに直近の結合で同じ言語を選びすぎないように制限する方式(hybrid+window)の比較です[8]。

トークナイザーはmC4で学習し、モデルはFineWeb2の1,000億トークンで学習しています。評価は22言語を対象とする12種類のベンチマークです。Table 1のトークナイザー単体の比較とは、語彙学習用のデータとPA-BPEの方式が異なります。

  1. [8] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026.

7. 既存BPEの統合・拡張

7.1. 結合規則の競合と継続BPE学習

学習済みモデルを新しい言語へ対応させる方法の1つが、既存の語彙とIDを残したトークンの追加です。別に学習した語彙や規則を足すと、元の結合規則との競合によって、追加したトークンを使えなくなることがあります。以下では§2.1と同じ、隣接するIDのペアを明示した規則を使います。
元のトークナイザーがa + b → abを持ち、追加元がb + c → bcとa + bc → abcを持っているとします。共通の文字には同じIDを使い、結合規則は次の3つだけにして、元の規則を優先します。
順位結合規則規則の出所
0a + b → ab元のトークナイザー
1b + c → bc追加元のトークナイザー
2a + bc → abc追加元のトークナイザー
この規則では、入力abcの結合はa | b | c → ab | cで止まります。先にabを作ると、b + c、続くa + bcを結合できなくなり、語彙にあるabcへ到達できません。この例なら、実際の分割に合うab + c → abcを加えることで、abcまで結合できます。
Purasonらの継続BPE学習(Findings of EACL 2026)[9]は、新しい言語や分野のデータを既存のトークナイザーで分割し、そのID列からBPEの学習を続けます。既存の分割で隣接するペアを数えるので、そこから適用できる結合規則を追加できます。例のab | cなら、候補になるのはab + cです。事前分割の境界など、元のトークナイザーの制約も引き継ぎます。
拡張後は、追加した文字列を単独で入力する場合と、文章に含める場合の両方で分割を確かめます。実装によっては、結合の前に断片全体を語彙と照合する処理があり、単独では1トークンになっても、より長い断片の一部になると結合規則が使われるためです。

Hugging Face Tokenizers 0.22.1のBPEでは、BPE-dropout(§8.3)を使わず、ignore_merges=Trueにすると、事前分割した断片全体が語彙にあれば直接そのIDを返します[20]。表の3規則と初期文字xを持つ例では、abcは直接照合で1トークンになります。語彙にないxabcを1つの断片として渡すと結合規則が使われ、x | ab | cになります。

tiktoken 0.12.0も断片全体を直接照合します。さらに、通常の結合候補はIDペアの表ではなく、隣接トークンを連結したバイト列の順位表で調べます[16]。したがって、本文のa + bcという特定の組だけを登録する例とは、規則の表し方が異なります。

配布コードを実行すると、本文の明示的なペア規則による例をresults/integration_conflicts.jsonで確認できます。

  1. [20] Hugging Face, "Tokenizers: BPE model (v0.22.1)," GitHub, 2025.
  2. [16] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.

7.2. モデルの入出力との整合性

追加したトークンを既存モデルで使うには、新しいIDに対応する入力埋め込みと出力行列の重みを用意します。既存IDを保てば、元の重みを残して新しい行を追加できます。初期化の一例は、新しいトークンを元のトークナイザーで分割し、対応するベクトルを平均する方法です[9]。その後、新しいトークンを含むID列で継続事前学習を行います。
分割が変わると、モデルが受け取るID列と各トークンの位置も変わります。出力候補の増加は、スコアを確率に変換するsoftmaxの分母を変え、既存トークンの予測確率にも影響します。このため、拡張後の品質は、新しく対応する言語と引き続き使う既存言語の両方で評価します。

8. 他の分割手法とBPEの拡張

8.1. WordPiece・Unigramとの比較

可変長のトークンでテキストを表す方式には、WordPieceやUnigramもあります。BPEとの主な違いは、語彙を作る方法と、その語彙から分割を選ぶ方法です。
方式語彙の学習学習後の代表的な分割
BPE頻出する隣接ペアを順に結合学習した順位で結合
WordPieceGoogleの機械翻訳システムGNMTでは、言語モデルが学習データに与える確率の改善を基に候補を追加[10]BERTの公開実装では左から最長一致
Unigram候補ごとの確率を推定し、語彙を段階的に絞り込み[12]トークンの確率の積が最大になる分割
BERTのWordPieceは左から最長一致で分割し、単語途中の断片には##を付けて語彙と照合します[11]。Unigramは、各トークンに割り当てた確率の積を分割全体の確率とし、それが最大になる組み合わせを動的計画法で求めます[12]。

8.2. 国内外のLLMでの採用例

2026年10月に公開資料で確認した国内外のモデルの採用例では、GPT-5やLlama 4がBPE、LLM-jp 4.1がUnigramを使っています。PLaMo 2・3は、Unigram系の独自実装を採用しています。

2025年以降に公開されたモデルを中心に、トークナイザーの設定と実装を確認しました。国内の例は、海外モデルを日本語で継続事前学習した系列を除いています。Hugging Face TokenizersのJSON形式ではmodel.type、SentencePiece形式ではtrainer_spec.model_typeを読み、独自実装では分割手順を確認しています。

開発地域モデル方式
海外GPT-5[21, 16]BPE
海外Llama 4[22]BPE
海外Qwen3[23]BPE
海外DeepSeek-V3.2[24]BPE
国内PLaMo 2・3[25, 26]Unigram系
国内LLM-jp 4.1[27]Unigram
国内Sarashina2.2-3B[28]Unigram
国内Stockmark-2-100B-Instruct[29]BPE

PLaMo 2・3は、トークンごとのスコアの和を基に分割全体を動的計画法で選ぶことから、ここではUnigram系に分類しています。PLaMo 2では、整数演算を使い、同点のときは先頭側の長いトークンを優先して、分割を一定にする工夫が加えられています[25]。llama.cppのPLaMo 3対応実装もこの分割処理を使い、さらに事前分割を行います[26]。

  1. [21] OpenAI, "tiktoken: Model-to-encoding mappings (v0.12.0)," GitHub, 2025. v0.12.0のモデル対応表では、GPT-5にo200k_baseを指定しています。
  2. [16] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.
  3. [22] Meta, "Llama 4: Tokenizer implementation," GitHub, 2025. BPEの順位表を読み込み、tiktokenに渡す実装です。
  4. [23] Qwen Team, "Qwen3 Technical Report," arXiv:2505.09388, 2025. §2でバイト単位のBPEの採用を明記しています。
  5. [24] DeepSeek, "DeepSeek-V3.2: tokenizer.json," Hugging Face, 2025. model.typeはBPEです。
  6. [25] imos, "PLaMo 2 tokenizer: Differences from the Unigram implementation," llama.cpp pull request #14560, 2025.
  7. [26] llama.cpp contributors, "llama.cpp: PLaMo 2 and PLaMo 3 tokenizer implementation," GitHub, 2026. llm_tokenizer_plamo2と、PLaMo 2・3の初期化処理を参照しています。
  8. [27] LLM-jp, "LLM-jp-4.1-8B-Thinking Model Card," Hugging Face, 2026. Tokenizer節でUnigramとbyte fallbackの採用を明記しています。
  9. [28] SB Intuitions, "Sarashina2.2-3B: SentencePiece tokenizer model," Hugging Face, 2025. trainer_spec.model_typeはUNIGRAMです。
  10. [29] Stockmark, "Stockmark-2-100B-Instruct: tokenizer.json," Hugging Face, 2025. model.typeはBPEです。

8.3. モデル学習時の確率的な分割

言語モデルが特定の分割に依存するのを抑えるため、語彙を固定したまま、同じ文を異なる分割で学習させる方法もあります。Unigramを使うsubword regularizationは、各トークンの確率に基づいて分割を無作為に選びます[12]。BPE-dropoutは、分割時に結合候補を一定の確率で一時的に除くことで、同じ入力から複数の分割を得ます[13]。評価時には通常、この確率的な選択を止め、同じ入力に同じ分割を返します。

8.4. 単語をまたぐ結合とバイトを直接扱うモデル

§3.2の事前分割の制約を緩めれば、BPEで複数の単語を1トークンにまとめられます。SuperBPE(COLM 2025)は、語彙学習の初めは単語内で結合し、途中から空白をまたぐ結合を許す方式です。よく一緒に現れる語の並びも、1つのトークンとして語彙に加えます[14]。
BPEのような可変長トークンの語彙を学習せず、バイト列を直接受け取るモデルもあります。Byte Latent Transformer(BLT、ACL 2025)は、次のバイトの予測の難しさに応じて、入力を可変長のまとまり(パッチ)に区切ります。各パッチを局所的な処理でベクトルへ変換し、大きなTransformerには短くなったベクトル列を渡します[15]。バイト単位で入力を受けつつ、計算量の大きい処理の単位を減らす設計です。

おわりに

多言語対応を考えるときは、文字を欠落なく表せることと、短いトークン列で表せることを分けて確認できます。用途に近い対訳文で分割の偏りを確かめれば、学習比率を変えるか、PA-BPEで語彙を配分するか、既存のBPEを拡張するかを検討できます。その変更でモデルが扱うID列も変わるため、採用の判断には各言語の品質と実際の処理コストまで含めます。

参考文献

  1. [1] Philip Gage, "A New Algorithm for Data Compression," The C Users Journal, 12(2), 1994. バイト列の頻出ペアを未使用のバイト値で置き換える圧縮方式として提案しています。
  2. [2] Rico Sennrich, Barry Haddow, Alexandra Birch, "Neural Machine Translation of Rare Words with Subword Units," ACL, 2016. §3.2、Algorithm 1。文字単位のBPEをニューラル機械翻訳へ適用した原著です。
  3. [3] Alec Radford, Jeffrey Wu, Rewon Child, David Luan, Dario Amodei, Ilya Sutskever, "Language Models are Unsupervised Multitask Learners," OpenAI Technical Report, 2019. §2.2。GPT-2のバイト単位のBPEと事前分割を説明しています。
  4. [4] François Yergeau, "UTF-8, a transformation format of ISO 10646," RFC 3629, 2003.
  5. [5] Hugging Face, "The tokenization pipeline," Tokenizers Documentation, 2026.
  6. [6] Ken Whistler, "Unicode Normalization Forms (Unicode 18.0.0, Revision 58)," Unicode Standard Annex #15, 2026.
  7. [7] Craig W Schmidt, Varshini Reddy, Haoran Zhang, Alec Alameddine, Omri Uzan, Yuval Pinter, Chris Tanner, "Tokenization Is More Than Compression," EMNLP, 2024. 3.5億〜24億パラメーターの64モデルを使い、分割方法などとモデル品質の関係を比較しています。
  8. [8] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026. ACL 2026最終版。学習手順は§4、圧縮・Gini係数はTable 1、モデル品質はTable 2を参照してください。
  9. [9] Taido Purason, Pavel Chizhov, Ivan P. Yamshchikov, Mark Fishel, "Teaching Old Tokenizers New Words: Efficient Tokenizer Adaptation for Pre-trained Models," Findings of EACL, 2026. 継続BPE学習と、語彙削減時の依存関係を扱っています。
  10. [10] Yonghui Wu et al., "Google's Neural Machine Translation System: Bridging the Gap between Human and Machine Translation," arXiv:1609.08144, 2016. §4.1のWordPieceの学習方法を参照しています。
  11. [11] Google Research, "BERT: WordpieceTokenizer," GitHub, 2018.
  12. [12] Taku Kudo, "Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates," ACL, 2018.
  13. [13] Ivan Provilkov, Dmitrii Emelianenko, Elena Voita, "BPE-Dropout: Simple and Effective Subword Regularization," ACL, 2020.
  14. [14] Alisa Liu, Jonathan Hayase, Valentin Hofmann, Sewoong Oh, Noah A. Smith, Yejin Choi, "SuperBPE: Space Travel for Language Models," COLM, 2025.
  15. [15] Artidoro Pagnoni, Ramakanth Pasunuru, Pedro Rodriguez, John Nguyen, Benjamin Muller, Margaret Li, Chunting Zhou, Lili Yu, Jason E Weston, Luke Zettlemoyer, Gargi Ghosh, Mike Lewis, Ari Holtzman, Srini Iyer, "Byte Latent Transformer: Patches Scale Better Than Tokens," ACL, 2025.