1. BPE によるトークン化

基本的な流れ

BPE はテキストを 単語単位ではなく隣接ペアの頻度 でマージします。 初期状態では各文字(バイト)が1つのトークンです。

入力: t h i s _ i s _ a _ p e n

1. "is" が2回出現 → 最頻出ペア → ID 256 = "is" にマージ
2. t h [is] _ [is] _ a _ p e n

3. 以降も頻出ペアを繰り返しマージ

ID の割り当て

範囲 内容
ID 0 〜 255 基本バイト(固定)
ID 256 〜 N BPE マージで追加されたトークン

2. UTF-8 によるバイト区別

UTF-8 は Unicode (コードポイント)を 1 - 3 バイトの可変長で符号化します。
UTF-8 はバイトの先頭ビットで役割が重複しない設計になっています。

バイト種別 ビットパターン 範囲
ASCII 1バイト文字 0xxxxxxx 0x00〜0x7F
先頭バイト(2バイト文字) 110xxxxx 0xC0〜0xDF
先頭バイト(3バイト文字) 1110xxxx 0xE0〜0xEF
先頭バイト(4バイト文字) 11110xxx 0xF0〜0xF7
継続バイト 10xxxxxx 0x80〜0xBF

例:cat vs 猫

"cat"
  c = 0x63 → 01100011(1バイト文字)
  a = 0x61 → 01100001(1バイト文字)
  t = 0x74 → 01110100(1バイト文字)

"猫"
  0xE7 → 11100111(3バイト文字の先頭)
  0xAC → 10101100(継続バイト)
  0xAB → 10101011(継続バイト)

※ 0x は 16 進数表記を表します

3つの範囲が完全に重複しないため、BPE がバイト列を扱っても混同されないません。

3. トークン ID が Embedding に渡るまで

入力テキスト
    ↓
1. トークナイザー( BPE )
  テキスト → トークン ID 列
  例: "猫は可愛い" → [42567, 11245, 98, 334]
    ↓
2. Embedding レイヤー
  トークン ID → 高次元ベクトル
  例: 42567 → [0.23, -0.41, 0.87, ...] (768次元など)
    ↓
3. Transformer ブロック

Embedding レイヤーの実体

語彙数 × 埋め込み次元 の巨大な参照テーブル(行列)です。 トークン ID は単なる 行番号(インデックス) として使われます。

役割の分離

役割 内容
BPE 「どの ID を割り振るか」を決める(学習前に決定)
Embedding 「その ID がどんな意味か」を学習で獲得する

4. 語彙数

$語彙数 = 256 + マージ回数$ です。
マージ回数は事前に決めるハイパーパラメータです。

モデル 語彙数
GPT-2 50,257
LLaMA 3 128,256
cl100k(GPT-4) 100,277

トレードオフ

語彙数 メリット デメリット
大きい 1トークンで長い単語を表現できる Embedding テーブルが大きくなりメモリ増加
小さい メモリ節約 1つの単語が多くのトークンに分割される

5. 未知語の処理

学習時に存在しなかった語彙が推論時に入力された場合の優先順位:

入力文字列
    ↓
1. BPE の既知トークンに一致するか? → 一致すればそのID
    ↓ 一致しない
2. より短い BPE トークンに分解できるか? → 分解して ID 列
    ↓ それも無理
3. 1バイトずつ分解 → ID 0〜255 の基本バイト

Byte-level BPE であれば、どんな入力でも必ず 0〜255 のバイトに分解できるため未知語が原理的に発生しません。

ただし意味的には

状況 品質
既知トークン “東京” 学習で意味を獲得済みなので良い
バイト分解 [0xE7, 0xB4, …] 文脈から推測するしかないので悪い️

学習時に十分出現していた語彙ほど良い Embedding を持ちます。