交差エントロピー $H(p,q)$ は、確率分布 $q$ から発生する情報量符号長)$I(x) = -\log_2 q(x)$ を、真の確率 $p(x)$ で重み付けして平均をとったものです。つまり $q$ の情報量符号長)を $p$ に従って発生したときに使うと、平均何ビット必要なのかを表しています。

\[\begin{aligned} H(p,q) = - \sum_{x} p(x) \log_2 q(x) \quad \text{離散確率変数} \\ H(p,q) = - \int\limits_x p(x) \log_2 q(x) dx \quad \text{連続確率変数} \\ \end{aligned}\]

期待値を使って $\mathbb{E}_{x \sim p}[-\log_2 q(x)]$ とも書きます。

$p=q$ なら、割り当てた符号長がその事象の真の分布と合っているので、平均符号長は最小の $H(p)$ になります($H(p,q)=H(p)$)。

$p \neq q$ だと、符号長の割り当てが実際の起こりやすさと乖離しているため平均符号長は $H(p)$ より大きくなります。 その差が KLダイバージェンス($D_{\text{KL}}(p\parallel q)$)です。

交差エントロピー $H(p,q)$ は KLダイバージェンス($D_{\text{KL}}(p\parallel q)$)を用いて以下のように表すことができます。

\[\begin{aligned} H(p, q) = H(p) + D_{\text{KL}}(p \parallel q) \\ D_{\text{KL}}(p \parallel q) = H(p,q) - H(p) \geq 0 \\ p=q \Rightarrow D_{\text{KL}}(p\parallel q) = H(p,q)=H(p) = 0 \end{aligned}\]

交差エントロピー誤差(損失関数・誤差関数)

交差エントロピーは、2 つの確率分布の乖離を評価できるため、Deep Learning の分類問題の損失(誤差)関数(Loss Function)として使用されます(誤差関数を強調する意味で交差エントロピー誤差(Cross-Entropy Error / Cross-Entropy Loss)と呼ぶことが多いようです)。

  • $p(x)$(現実の分布):正解データ(正解ラベル)の分布
  • $q(x)$(モデルの分布):モデルが出力した予測(Softmax 関数を通した確率)の分布

[!NOTE] Deep Learning の実装(PyTorchなど)では、情報理論で一般的な底が $2$ の対数($\log_2$)ではなく、自然対数($\log_e$ または $\ln$)が使われます。以降の計算例では自然対数を使用します。

コンテキスト長 $C$ 内の「ある 1 つの位置(トークン位置)$t$」に注目したときの、Deep Learning のモデルの分布と正解データの関係性は以下の通りです。

1. モデルの出力(予測確率分布: $q_t$)

各位置 $t$ において、モデルは次に続くトークンの予測として、語彙数(Vocabulary Size: $V$)と同じ次元数を持つ確率分布を出力します。

\[q_t^i = (q_t^1,\ q_t^2,\ \dots,\ q_t^V), \quad \sum_{i=1}^V q_t^i = 1\]

2. 正解データ(one-hotベクトル: $p_t$)

正解データ(次に実際に来た単語)を、語彙数 $V$ の次元を持つ One-Hotベクトル(正解の単語のインデックスだけが 1 で、他はすべて 0 のベクトル)として表現します。

\[p_t = (0, 0, \dots, 1, \dots, 0), \quad \sum_{i=1}^V p_t(i) = 1\]

3. 交差エントロピー誤差($L_t$)の計算

\[L_t = - \sum_{i=1}^{V} p_t(i) \log q_t(i)\]

正解の one-hotベクトル $p_t$ は正解ラベル($k_t$ 番目)以外すべて $0$ になるため、正解トークンの項だけが残ります。

\[L_t = - \log q_t(k_t)\]
  • $q_t(k_t)$ が $1$ に近づくほど、損失(誤差)は $0$ に近づきます
  • $q_t(k_t)$ が $0$ に近づくほど、損失(誤差)は無限大に向かって大きくなります

4. 全体(バッチとコンテキスト)での損失の集約

LLM の学習は入力データのシェイプであるバッチ数 $N$ とコンテキスト長 $C$ の損失を一括で計算します。

  1. すべての位置での計算: バッチ内の各サンプル $n$($1$ から $N$)の、各トークン位置 $t$($1$ から $C$)のすべてにおいて、上記の一連の交差エントロピー損失 $L_{n, t}$ を計算します。
  2. 平均値の算出: すべての位置の損失の平均値をとり、全体の総損失(Total Loss)とします。

つまり総損失(Total Loss)を交差エントロピー誤差の平均値と定義します。

\[\text{Total Loss} = \frac{1}{N \times C} \sum_{n=1}^{N} \sum_{t=1}^{C} L_{n, t} = \frac{1}{N \times C} \sum_{n=1}^{N} \sum_{t=1}^{C} -\log q_t(k_t)\]

この全体の平均損失(Total Loss)が小さくなるように、バックプロパゲーション(誤差逆伝播法)によって Transformer 内部のパラメータ(重み)が更新されていきます。

交差エントロピー誤差とマルチヌーイ分布の負の対数尤度の関係

以下では、バッチ内の 1 サンプル($N=1$)、すなわちコンテキスト長 $C$ の 1 系列に注目して、交差エントロピー誤差と負の対数尤度(NLL:Negative Log-Likelihood)の対応を確認します。上の「4.」で扱ったバッチ次元 $N$ 方向の平均は、この 1 系列分の Total Loss をさらにサンプル間で平均したものに相当します。

設定

  • LLM はコンテキスト長 $C$ 個のトークン ID 列を入力とし、各位置で語彙数 $V$ 次元の確率分布を出力する
  • 位置 $t$ のトークンの正解分布を $p_t$、モデルの予測分布を $q_t$ とする
  • 正解トークンのインデックスを $k_t$ とする

1. 交差エントロピー誤差

位置 $t$ のトークンに対する交差エントロピー誤差は次式で定義されます。

\[L_t = - \sum_{i=1}^{V} p_t(i) \log q_t(i)\]

2. one-hot ベクトルによる簡略化

正解分布 $p_t$ は $k_t$ 番目だけが $1$、それ以外は $0$ の one-hot ベクトルであるため、和の中で $i = k_t$ の項のみが残ります。

\[L_t = - p_t(k_t) \log q_t(k_t) = - \log q_t(k_t)\]

3. 系列全体の平均損失

\[\text{Total Loss} = \frac{1}{C} \sum_{t=1}^{C} L_t = \frac{1}{C} \sum_{t=1}^{C} \left( - \log q_t(k_t) \right)\]

4. マルチヌーイ分布の負の対数尤度との対応

各位置 $t$ の予測分布 $q_t$ は、語彙数 $V$ のどれが出現するかを表すマルチヌーイ(カテゴリカル)分布のパラメータです。 正解トークン $k_t$ が観測される尤度は以下の式で表されます。

\[P(k_t \mid q_t) = q_t(k_t)\]

負の対数尤度は交差エントロピー誤差と一致します。

\[- \log P(k_t \mid q_t) = - \log q_t(k_t) = L_t\]

各トークンが条件付きで独立に生成されると仮定すると、系列全体の同時尤度は以下のとおりです。

\[P(\text{系列}) = \prod_{t=1}^{C} q_t(k_t)\]

同時尤度を負の対数尤度に変換します。

\[- \log \prod_{t=1}^{C} q_t(k_t) = \sum_{t=1}^{C} \left( - \log q_t(k_t) \right)\]

これは系列全体の(厳密な)負の対数尤度そのものであり、$\dfrac{1}{C}$ はまだ現れません。総損失(Total Loss)は「1トークンあたりの平均負の対数尤度」として定義されるため、これを $C$ で割ります。

\[\text{Total Loss} = \frac{1}{C} \sum_{t=1}^{C} \left( - \log q_t(k_t) \right) = \frac{1}{C}\left(-\log P(\text{系列})\right)\]

結論

\[\text{交差エントロピー最小化} \iff \text{最尤推定(尤度最大化)}\]

トークンごとの交差エントロピー誤差の平均は、モデルの出力をマルチヌーイ分布の集合とみなしたときの、系列全体に対する負の対数尤度の平均と数学的に一致します。

モンテカルロ積分によるクロスエントロピーの近似

クロスエントロピー $H(p,q) = - \int p(x) \log_2 q(x) dx$ を解析的に求めることが困難な場合、モンテカルロ積分を用いて近似します。

モンテカルロ積分では、真の分布 $p(x)$ による期待値を、真の分布から抽出されたデータ $D={x_{1},\ldots,x_{n}}$(ただし $x_i \sim p(x)$)の標本平均に置き換えます。

\[H(p,q) \approx - \frac{1}{n} \sum_{i=1}^n \log_2 q(x_i)\]

データ数 $n$ で割ることで、サンプルの平均(期待値の近似値)を求めます。

対数の性質を利用すると、以下のように変形することもできます。

\[\begin{aligned} H(p,q) &\approx - \frac{1}{n} \sum_{i=1}^n \log_2 q(x_i) \\ &= - \frac{1}{n} \log_2 \prod_{i=1}^n q(x_i) \end{aligned}\]

Python コード

\[L = -\sum_{k=0}^{n} t_k \log y_k\]

(本文中の記法とは異なり、この式のみ $0$ 始まり・上限 $n$ の慣習で書いています。)

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    # 正解データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]

    # np.log(0) はマイナス無限大(-inf)になり、計算が止まってしまいます。
    # それを防ぐために、ごく小さな値(1e-7)を足して、絶対に 0 にならないように安全策をとっています。

    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

出典:ゼロから作るDeep Learning ❷ ―自然言語処理編 斎藤康毅 (著)