🎓 レベル:基礎 | 重要度:A(必須)
📎 前提:Transformer・自己回帰モデル
要点(BLUF)
- 大規模言語モデル(LLM)の正体は、大きな Transformer を「次のトークンを当てる」一点に特化させた自己回帰モデルです。言語モデルとは「直前までの並びから次の token の確率分布 を出す関数」にすぎません(自己回帰モデル)。
- 推論は 「テキスト → トークン化 → 埋め込み → Transformer → 次トークンの分布 → サンプリング → 1個追加 → 繰り返し」 という1本のループ。これが廃れにくい骨格で、規模や細部が変わってもこの流れは共通です。
- 文字でも単語でもなくサブワードで区切るのが現代LLMの定番です。語彙サイズと未知語・希少語の扱いのバランスを取るための選択です。
1. LLM とは:「次トークン予測」に尽きる
LLM を一言でいうと、巨大な Transformer + 次トークン予測です。難しそうな見た目に反して、やっていることは一つの条件付き分布を出すことだけです。
言語モデル(language model)は、トークン列 に対して、次のトークンの確率分布を返す関数として定義されます。
そして文全体の確率は、自己回帰モデルで見た**乗法定理(チェインルール)**でそのまま積に分解されます。
要するに: 「文を生成する」という大層なタスクは、「前を見て次の1個を当てる」を左から右へひたすら繰り返すことに完全に等しい、というのが出発点です。近似は入っていません。LLM が学習するのは、この各因子 を Transformer で表現することだけです。
自己回帰分解そのものの理屈(なぜ厳密尤度が計算できるか、teacher forcing、逐次生成が遅い理由)は 自己回帰モデル に書いたので、ここでは繰り返しません。本ノートは「要素=トークン・本体=Transformer」にしたLLM版の具体に焦点を当てます。
2. トークン化(tokenization):なぜサブワードか
LLM はテキストを直接は扱えません。まずトークンという離散単位の列に区切り、各トークンに整数ID(token ID)を振ります。この区切り方の粒度に、3つの選択肢があります。
| 粒度 | 語彙サイズ | 系列長 | 未知語・希少語 |
|---|---|---|---|
| 文字単位(character) | 小さい(数百〜数千) | 非常に長くなる | 未知語は出ないが、意味の単位が細かすぎる |
| 単語単位(word) | 巨大(数十万〜) | 短い | 未知語(OOV)が必ず出る・活用形が爆発する |
| サブワード(subword) | 中庸(数万程度) | 中庸 | 希少語を部分に分解して表現できる |
現代のLLMはほぼ例外なくサブワードを採用します。理由は上の表のトレードオフにあります。
- 単語単位の問題:語彙を有限にすると、学習時に見なかった単語(OOV; out-of-vocabulary)を全部「不明トークン」に潰すしかなく、情報が失われます。かといって語彙を増やすと、出力ソフトマックスの幅(後述)が肥大化します。
- 文字単位の問題:未知語は原理的に出ませんが、系列がとても長くなり、Transformer の計算コスト(注意機構は系列長に対して重い)と、長距離依存の学習が厳しくなります。
- サブワードの落とし所:頻出語は1トークンのまま、希少語や未知語は「意味のある部分文字列」に分解します。たとえば “tokenization” が
token+izationのように割れるイメージです。未知語を完全に避けつつ、語彙サイズと系列長を中庸に保てるのが利点です。
BPE(Byte-Pair Encoding)の考え方
代表的な学習法が BPE(バイト対符号化) です。発想は素朴で、「よく隣り合う組をくっつけて1つの語彙にする」を繰り返すだけです。
- 最初は全テキストを最小単位(文字、あるいはバイト)に分解する
- コーパス中で最も頻繁に隣接して現れるペアを1つ見つけ、それを新しい1トークンとして語彙に追加(マージ)する
- 目標の語彙サイズに達するまで 2 を繰り返す
要するに: 頻出する並びほど早く1トークンにまとまるので、ありふれた語は短く、珍しい語は細かい部品の列になります。語彙サイズという「予算」の中で、頻度の高いものを優先的に1単位へ昇格させる貪欲なアルゴリズムです。
⚠️ 要最新確認:具体的にどのトークナイザ(BPE / WordPiece / Unigram / byte-level BPE など)を使うか、語彙サイズが何万か、特殊トークンの設計などはモデルごとに異なり、世代ごとに変わります。「サブワードで区切る」「頻度ベースでマージする」という原理は安定していますが、個別スペックは採用モデルのドキュメントで確認してください。
3. 埋め込み(embedding):token → ベクトル
トークンID(ただの整数)のままでは計算できないので、各IDを密ベクトルに変換します。これが**埋め込み(embedding)**です。
- 語彙サイズ 、埋め込み次元 の埋め込み行列 を用意し、トークンID に対して の第 行 を取り出します。
- この行列 は学習で決まるパラメータです。意味の近いトークンが近いベクトルになるよう訓練の中で配置されます(→ 表現学習と埋め込み)。
- Transformer 自身は順序の情報を持たないため、各位置に**位置情報(positional encoding/embedding)**を足し込みます。「どのトークンか」を表す埋め込みに「何番目か」を表す情報を加える、という二段構えです。
要するに: トークン化が「言葉を離散IDに落とす」工程、埋め込みが「そのIDを意味を持った連続ベクトルに引き上げる」工程です。ここから先は全部ベクトルの計算になります。
4. 推論の流れ:自己回帰ループ
ここまでの部品を一本につなぐと、LLM の推論(生成)パイプラインができます。入力を1度処理して、あとは1トークンずつ生成して継ぎ足す——これがすべてです。
flowchart LR
IN["入力テキスト(プロンプト)"] --> TOK["トークン化(サブワードIDの列)"]
TOK --> EMB["埋め込み(ID→ベクトル + 位置情報)"]
EMB --> TR["Transformer(マスク付き自己注意の多層)"]
TR --> DIST["最終位置の次トークン分布 p(xt | x<t)"]
DIST --> SAMP["サンプリング(次の1トークンを選ぶ)"]
SAMP -->|"選んだトークンを末尾に追加"| APP["系列を1つ伸ばす"]
APP -->|"停止条件まで繰り返す(自己回帰)"| EMB
APP --> OUT["出力テキスト"]
各ステップを言葉にすると:
- トークン化:入力テキストをサブワードIDの列にする。
- 埋め込み:各IDをベクトルに変換し、位置情報を加える。
- Transformer 本体:マスク付き自己注意(Transformer)を多層通す。因果マスクにより「各位置から見えるのは自分以前のトークンだけ」が保証され、未来を盗み見できません。
- 次トークンの分布:最後の層が各語彙トークンのロジット を出し、ソフトマックスで確率分布に変換します。
要するに: Transformer の出力(生のスコア=ロジット)を、足して1になる確率に正規化したものが「次に来るトークンの確率」です。 5. サンプリング:この分布から次の1トークンを選ぶ。常に最大確率を選べば貪欲法(greedy)、確率に従って引けばランダムサンプリング。温度 を入れた
で揺らぎの大きさを調整できます( で貪欲、 を上げるほど分布が平らになり多様性が増す)。 6. 継ぎ足してループ:選んだトークンを系列の末尾に足し、停止トークンや上限長まで 2〜5 を繰り返す。これが自己回帰生成です。
プレフィルとデコード:並列と逐次
実装上、このループは2つの局面に分かれます。原理を理解するうえで効く区別です。
- プレフィル(prefill):入力プロンプトは最初から全部揃っているので、全トークンを並列に1回通せます。ここで各層の中間表現を計算し、いわゆる KVキャッシュ に蓄えておきます。
- デコード(decode):そこから先は1トークンずつ逐次。新しいトークンを1個出すたびに末尾へ足し、また1回フォワードする——ここは原理的に直列で、 トークン生成には 回のステップが要ります(自己回帰モデルの「逐次で遅い」がそのまま効く)。KVキャッシュは過去分の再計算を省くための工夫です。
要するに: 「与えられた文脈を読む」のは並列で速く、「続きを書く」のは1文字ずつしか進めない、という非対称があります。LLM の推論コストやレイテンシの話は、ほぼこの「逐次デコード」が源です(詳細な最適化は要最新確認)。
5. 文脈窓(context window)
LLM が一度の推論で扱えるトークン数の上限を**文脈窓(context window)**と呼びます。
- 入力プロンプトと生成した出力を合わせて、この上限トークン数までしか「同時には」見られません。
- LLM は呼び出しをまたいで状態を保持しないため、会話を続けるには過去のやり取りを毎回まるごと入力に詰め直すのが基本です。その全体が文脈窓に収まっている必要があります。
- 注意機構は系列長に対して計算が重くなる(素朴には二乗オーダー)ため、文脈窓を伸ばすことは技術的な課題であり続けています。
要するに: 文脈窓は「モデルの作業机の広さ」です。机からあふれた古い情報はその推論では考慮されません。
⚠️ 要最新確認:文脈窓が何トークンか(数千〜数百万まで世代差が大きい)、長文脈をどう実現しているかはモデル・バージョンごとに激しく変わります。最新値は採用モデルの公式情報で確認してください。
⚠️ よくある誤解・要最新確認
- LLM は検索エンジンではありません。 データベースを引いて答えを「検索」しているのではなく、学習で身につけた分布 に従って次のトークンを確率的に生成しているだけです。だから事実を取り違える(ハルシネーション)ことがあり、出典を持っているわけでもありません。外部知識を引かせたい場合は別の仕組み(プロンプティングとIn-context learning や検索拡張)が要ります。
- 「賢い1回の出力」ではなく「1トークンずつの積み重ね」です。 モデルは文全体を一気に思いついているのではなく、毎ステップ次の1トークンの分布を出してサンプリングする、を繰り返しているだけです。長い応答も、この短い予測の連鎖でできています。
- 出力は確率的です。 温度やサンプリング方式しだいで、同じ入力でも出力が変わります。再現性が要る用途では貪欲法や温度0を使う、という調整が必要です。
- 具体的なスペックは廃れます。 モデルの規模(パラメータ数)、トークナイザの種類、語彙サイズ、文脈窓の長さといった数字や細部は世代ごとに変わるので、本ノートでは原理だけを扱い、個別値は要最新確認としています。安定して使えるのは「サブワード化 → 埋め込み → Transformer → 次トークン分布 → サンプリング → ループ」という骨格のほうです。
対応するシミュレーション
simulations/bpe_tokenization.py:LLMの入口で使われるサブワード分割(バイトペア符号化)を小さなコーパスで再現します。最初は文字単位から始め、「最も頻繁に隣り合うペア」を1つの新トークンに統合する、を繰り返すと、es→est→est_ のように頻出のかたまりが1トークンに育ち、コーパス全体の系列が短くなることを可視化します。未知語も既知の部分文字列に分解でき語彙の外に出ないのが利点です(温度サンプリングは 推論の実務)。
