Back to blog

LLMの頭の中を覗く — GPT-2 miniで見る「次の文字予測」の仕組み

自作GPT-2 miniの生成過程を可視化し、モデルがどのように確率分布を計算して次の文字を選んでいるか、Temperatureがどう影響するかを観測する

LLM は何をしているのか

ChatGPT や Claude などの LLM を使っていると、まるで「考えて」回答しているように見える。しかし、その本質は驚くほどシンプルだ。

次の文字(トークン)の確率分布を予測しているだけ

「私は」と入力すると、モデルは次に来る可能性のある全ての文字に対して確率を計算する。「猫」が 10%、「犬」が 5%、「人」が 3%… といった具合だ。

この仕組みを実際に目で見てみたい。前回作成した GPT-2 mini に可視化機能を追加した。

可視化スクリプト

生成の各ステップで以下を表示するスクリプトを作成した。

  • 現在のテキスト
  • 次の文字の候補(Top-10)と確率
  • 確率バー(視覚的な表現)
  • 実際に選ばれた文字

コードの核心部分を示す。

# Forward pass で logits を取得
logits, _ = model(idx_cond)
logits = logits[:, -1, :] / temperature

# softmax で確率分布に変換
probs = F.softmax(logits, dim=-1)

# Top-k の候補を取得
top_probs, top_indices = torch.topk(probs[0], k=10)

# 確率に基づいてサンプリング
idx_next = torch.multinomial(probs, num_samples=1)

重要なのは softmaxmultinomial だ。

  • softmax: logits を確率分布(合計 1)に変換
  • multinomial: 確率分布に従ってランダムにサンプリング

生成過程の実例

「私は」というプロンプトで生成した結果を見てみよう。

--- Step 1 ---
現在のテキスト: 「私は」

次の文字の候補(確率順):
----------------------------------------
   1. 「ま」         11.8% █████
   2. 「、」         11.3% █████
   3. 「そ」          9.4% ████
   4. 「な」          6.4% ███
   5. 「私」          5.7% ██
   6. 「あ」          5.0% ██
   7. 「い」          3.8% █
   8. 「何」          3.5% █
   9. 「少」          2.8% █
  10. 「こ」          2.8% █

>>> 選択された文字: 「私」(確率: 5.7%)

興味深い点がいくつかある。

  1. 確率が分散している: 最も高い「ま」でも 11.8% しかない
  2. 文法的に正しい候補が上位:「ま」「そ」「な」など、「私は〜」と続く自然な文字
  3. サンプリングの効果: 5 位の「私」が 5.7% の確率で選ばれた

文法を学習している証拠

次のステップを見ると、モデルが日本語の文法を学習していることがわかる。

--- Step 4 ---
現在のテキスト: 「私は私の顔」

次の文字の候補(確率順):
----------------------------------------
   1. 「を」         88.0% ████████████████████████████████████████████
   2. 「に」          3.3% █
   3. 「の」          2.5% █
   ...

>>> 選択された文字: 「を」(確率: 88.0%)

「顔」の後に「を」が来る確率は 88% だ。モデルは「名詞+を」という日本語の格助詞パターンを学習している。

同様に、「私は」の後に続く「は」も高確率で予測される。

現在のテキスト: 「私は私の顔を見た。私」

   1. 「は」         89.3% ████████████████████████████████████████████

これが LLM の「理解」の正体だ。統計的なパターンを学習し、文法的に正しい文字に高い確率を割り当てている。

Temperature の効果

Temperature は確率分布の「尖り具合」を制御するパラメータだ。

低い Temperature(0.3)

プロンプト: 「吾輩は猫」

--- Step 3 ---
   1. 「と」        100.0% ██████████████████████████████████████████████████
   2. 「ろ」          0.0%
   ...

確率が一点に集中し、ほぼ確定的に最も確率の高い文字が選ばれる。

結果:「吾輩は猫のごとく、吾輩の」

高い Temperature(1.2)

プロンプト: 「吾輩は猫」

--- Step 1 ---
   1. 「と」         16.4% ████████
   2. 「の」         15.2% ███████
   3. 「で」          9.1% ████
   4. 「に」          5.2% ██
   ...

確率が平坦化され、低確率の文字も選ばれやすくなる。

結果:「吾輩は猫にならなくってい」

Temperature の数学的意味

logits = logits / temperature
probs = F.softmax(logits, dim=-1)

softmax の前に logits を temperature で割っている。

  • T < 1: logits の差が拡大し、確率分布が尖り、確定的になる
  • T > 1: logits の差が縮小し、確率分布が平坦になり、ランダムになる
  • T → 0: argmax、最も確率の高い文字を常に選択
  • T → ∞: 一様分布、完全にランダム

学んだこと

1. LLM の本質は確率予測

「考えている」「理解している」ように見えるが、実際は次のトークンの確率分布を出力しているだけ。その確率が文法的に正しいパターンに高く割り当てられているから、自然な文章が生成される。

2. Temperature は創造性と安定性のトレードオフ

低い Temperature は安全だが退屈な出力になりやすい。高い Temperature は創造的だが、文法的に破綻しやすい。用途に応じて調整が必要だ。

3. 可視化の価値

ブラックボックスの中身を見ることで、「なぜその出力になったか」が理解できる。デバッグや改善のヒントにもなる。

使い方

可視化スクリプトは以下のように実行できる。

cd GPT-2mini

# 基本的な使い方
python visualize_generation.py \
  --load model_large.pt \
  --prompt '好きな文章' \
  --max_tokens 15 \
  --temperature 0.8 \
  --data data.txt

# Temperature を変えて比較
python visualize_generation.py --load model_large.pt --prompt '私は' --temperature 0.3 --data data.txt
python visualize_generation.py --load model_large.pt --prompt '私は' --temperature 1.2 --data data.txt

コードは GitHub で公開している。

次のステップ

  • Attention の重み可視化(どの文字を「見て」判断しているか)
  • BPE トークナイザーとの比較
  • より大規模なデータでの学習と品質変化の観測

LLM の仕組みを理解するには、実際に手を動かして観測するのが一番だ。