確率と情報理論 ── エントロピー・交差エントロピー・ソフトマックス
LLM との関係:LLM の出力は「次のトークンの確率分布」。訓練の目的関数は「交差エントロピー損失の最小化」。この章はその数学的基盤。

この章で何ができるようになるか:ソフトマックス関数がなぜ確率分布を作れるのか、交差エントロピー損失がなぜ「予測の良さ」を測れるのかを数式とコードで説明できる。
確率分布:LLM の出力の正体
LLM の出力は語彙全体に対する確率分布だ。
import numpy as np
# LLM の最終層の出力(logits):生のスコア
logits = np.array([2.0, 1.0, 0.1, 5.0, 3.0])
# 語彙: ["the", "a", "is", "Tokyo", "in"]
# → "Tokyo" のスコアが最も高い
# これは確率ではない(合計が1でない、負の値もありうる)
# → ソフトマックスで確率に変換する
ソフトマックス関数:スコアを確率に変換する
$$\text{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}}$$
def softmax(logits):
"""ロジットを確率分布に変換する"""
# 数値安定性のために最大値を引く(結果は同じ)
shifted = logits - np.max(logits)
exp_vals = np.exp(shifted)
return exp_vals / np.sum(exp_vals)
logits = np.array([2.0, 1.0, 0.1, 5.0, 3.0])
probs = softmax(logits)
# → [0.047, 0.017, 0.007, 0.936, 0.127] ではなく...
# 実際: [0.046, 0.017, 0.007, 0.843, 0.114] ← ちゃんと合計1.0
vocab = ["the", "a", "is", "Tokyo", "in"]
for word, prob in zip(vocab, probs):
print(f" {word}: {prob:.3f}")
# → Tokyo: 0.843(最も確率が高い → 出力される)
ソフトマックスの性質:
- 全ての出力が正(exp のおかげ)
- 合計が 1(正規化のおかげ)
- 大きいスコアの差がさらに強調される(exp は差を指数的に広げる)
Temperature:確率分布の「鋭さ」を制御する
def softmax_with_temperature(logits, temperature=1.0):
"""
temperature < 1: 分布が鋭くなる(最も確率の高いトークンに集中)
temperature > 1: 分布がなだらかになる(ランダム性が増す)
temperature → 0: 最大確率のトークンだけが選ばれる(greedy)
temperature → ∞: 一様分布(完全ランダム)
"""
scaled = logits / temperature
return softmax(scaled)
logits = np.array([2.0, 1.0, 0.1, 5.0, 3.0])
print("T=0.5 (sharp):", softmax_with_temperature(logits, 0.5))
# → Tokyo: 0.977(ほぼ確定)
print("T=1.0 (normal):", softmax_with_temperature(logits, 1.0))
# → Tokyo: 0.843
print("T=2.0 (flat):", softmax_with_temperature(logits, 2.0))
# → Tokyo: 0.494(他のトークンも選ばれやすい)
API パラメータの temperature はまさにこれ。 創造的な文章には高い temperature、事実に基づく回答には低い temperature を使う。
エントロピー:「驚き」の平均
情報理論の中核概念。確率分布の「不確実さ」を数値化する。
$$H(p) = -\sum_{i} p_i \log p_i$$
def entropy(probs):
"""確率分布のエントロピー(不確実性)"""
# log(0) を避けるため、0 に近い値にクリップ
probs = np.clip(probs, 1e-10, 1.0)
return -np.sum(probs * np.log(probs))
# 確定的な分布(1つのトークンが確実)
certain = np.array([1.0, 0.0, 0.0, 0.0, 0.0])
print(entropy(certain)) # ≈ 0(不確実性なし)
# 一様分布(全トークン等確率)
uniform = np.array([0.2, 0.2, 0.2, 0.2, 0.2])
print(entropy(uniform)) # ≈ 1.61(最大の不確実性)
# LLM の出力(Tokyo が高確率)
llm_output = np.array([0.046, 0.017, 0.007, 0.843, 0.087])
print(entropy(llm_output)) # ≈ 0.61(やや不確実)
直感:「次に来る単語がほぼ確定しているとき」エントロピーは低い。「どの単語が来てもおかしくないとき」エントロピーは高い。
交差エントロピー損失:LLM の目的関数
LLM の訓練は「交差エントロピー損失を最小化する」ことに尽きる。
$$\mathcal{L} = -\sum_{i} y_i \log \hat{y}_i$$
$y_i$ は正解ラベル(one-hot)、$\hat{y}_i$ はモデルの予測確率。
def cross_entropy_loss(predicted_probs, true_label_index):
"""
predicted_probs: モデルの出力確率分布
true_label_index: 正解トークンのインデックス
正解トークンに割り当てた確率が高いほど、損失が小さい
"""
prob_of_correct = predicted_probs[true_label_index]
return -np.log(prob_of_correct + 1e-10)
# モデルが "Tokyo" に 84% の確率を割り当てた場合
probs = np.array([0.046, 0.017, 0.007, 0.843, 0.087])
true_label = 3 # "Tokyo" のインデックス
loss = cross_entropy_loss(probs, true_label)
print(f"Loss: {loss:.4f}") # 0.1709(低い = 良い予測)
# モデルが "the" に高い確率を割り当ててしまった場合
bad_probs = np.array([0.7, 0.1, 0.05, 0.05, 0.1])
loss_bad = cross_entropy_loss(bad_probs, true_label)
print(f"Bad Loss: {loss_bad:.4f}") # 2.9957(高い = 悪い予測)
なぜ交差エントロピーが「良い」損失関数なのか
1. 正解の確率が 1.0 に近づくと損失が 0 に近づく(-log(1) = 0)
2. 正解の確率が 0 に近づくと損失が無限大に近づく(-log(0) → ∞)
→ 「絶対に間違えてはいけない」というペナルティが強い
3. 微分が綺麗(ソフトマックス + 交差エントロピーの勾配がシンプル)
→ 勾配降下法と相性が良い
Perplexity:LLM の「困惑度」
交差エントロピー損失を直感的に解釈する指標。
$$\text{PPL} = e^{\text{CrossEntropyLoss}}$$
def perplexity(avg_cross_entropy_loss):
return np.exp(avg_cross_entropy_loss)
# Loss = 3.0 → PPL = 20.1(20個の中から当てずっぽうに選ぶのと同程度の困惑)
# Loss = 2.0 → PPL = 7.4
# Loss = 1.0 → PPL = 2.7(2〜3個の選択肢で迷っている程度)
Perplexity = 20 は「次のトークンを20個の候補から均一に選ぶのと同じくらい迷っている」という意味。PPL が低いほど良いモデル。
GPT-4 クラスのモデルでは一般的な英語テキストに対して PPL ≈ 5〜15 程度。
Top-k サンプリングと Top-p(Nucleus)サンプリング
確率分布からどうトークンを選ぶか。
def top_k_sampling(logits, k=50, temperature=1.0):
"""上位 k 個のトークンだけを候補にし、その中からサンプリング"""
probs = softmax_with_temperature(logits, temperature)
top_k_indices = np.argsort(probs)[-k:] # 上位 k 個
top_k_probs = probs[top_k_indices]
top_k_probs /= top_k_probs.sum() # 再正規化
chosen = np.random.choice(top_k_indices, p=top_k_probs)
return chosen
def top_p_sampling(logits, p=0.9, temperature=1.0):
"""累積確率が p に達するまでのトークンを候補にする"""
probs = softmax_with_temperature(logits, temperature)
sorted_indices = np.argsort(probs)[::-1]
sorted_probs = probs[sorted_indices]
cumulative = np.cumsum(sorted_probs)
# 累積確率が p を超える最初のインデックス
cutoff = np.searchsorted(cumulative, p) + 1
top_indices = sorted_indices[:cutoff]
top_probs = probs[top_indices]
top_probs /= top_probs.sum()
return np.random.choice(top_indices, p=top_probs)
Top-p の利点:Top-k は固定数の候補しか見ないが、Top-p は「確率の分布に応じて」候補数が動的に変わる。確率が集中しているとき(確信があるとき)は少数の候補、分散しているときは多数の候補を見る。
まとめ
| 概念 | LLM での役割 | 数式 |
|---|---|---|
| ソフトマックス | ロジット → 確率分布 | $e^{z_i} / \Sigma e^{z_j}$ |
| Temperature | 出力の多様性制御 | logits / T |
| エントロピー | 予測の不確実性 | $-\Sigma p \log p$ |
| 交差エントロピー | 訓練の損失関数 | $-\Sigma y \log \hat{y}$ |
| Perplexity | モデルの「困惑度」 | $e^{\text{CE Loss}}$ |
| Top-k / Top-p | サンプリング戦略 | 候補の絞り込み |
次章では、これらの数学的道具を使って実際にニューラルネットワークがどう「学習」するか──パーセプトロンから誤差逆伝播法までを見ていく。