からっぽのしょこ

読んだら書く!書いたら読む!読書読読書読書♪同じ事は二度調べ(たく)ない

ソフトマックス関数と交差エントロピー誤差の逆伝播【ゼロつく1のノート(数学)】

はじめに

 「機械学習・深層学習」学習初手『ゼロから作るDeep Learning』民のための数学攻略ノートです。『ゼロつく1』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。

 NumPy関数を使って実装できてしまう計算について、数学的背景を1つずつ確認していきます。

 この記事は、主に5.6.3項「Softmax-with-Lossレイヤ」を補足するための内容になります。ソフトマックス関数と交差エントロピー誤差を合わせた順伝播の確認と逆伝播(微分)を導出します。

【関連する記事】

www.anarchive-beta.com

【他の記事一覧】

www.anarchive-beta.com

【この記事の内容】

ソフトマックス関数と交差エントロピー誤差の逆伝播

・順伝播の確認

 ソフトマックス関数とは次の式でした。順伝播については「ソフトマックス関数のオーバーフロー対策【ゼロつく1のノート(数学)】 - からっぽのしょこ」で解説しています。

$$ y_k = \frac{ \exp(a_k) }{ \sum_{k'=1}^{10} \exp(a_{k'}) } \tag{3.10} $$

 ここでソフトマックス関数の入力$\mathbf{a} = (a_1, a_2, \cdots, a_{10})$は、Affineレイヤの出力(重み付き信号とバイアスの和)です。$k$番目の要素は、$a_k = \sum_{i=1}^M x_{j} w_{ji} + b_i$で計算されます。また要素数が10なのは、0から9の数字の数に対応しています。

 この関数の計算を分解すると、入力$a_k$に対して分子は「指数をとる」「分母を掛ける」、分母は「指数をとる」「総和をとる」「割る」「分子と分母を掛ける」の4つのステップになります。

 交差エントロピー誤差は次の計算式で求まります。順伝播については「損失関数【ゼロつく1のノート(数学)】 - からっぽのしょこ」で解説しています。

$$ L = - \sum_{k=1}^{10} t_k \log y_k $$

 ここで、$\mathbf{y} = (y_1, y_2, \cdots, y_{10})$はソフトマックス関数の出力、$\mathbf{t} = (t_1, t_2, \cdots, t_{10})$は教師ラベルです。

 この関数の計算を分解すると、入力$y_k$に対して「対数をとる」「$t_k$を掛ける」「総和をとる」「-1を掛ける」の4つのステップになります。

 それぞれの関数内での逆伝播を求めましょう。後から伝播してくるので、まずは交差エントロピー誤差から計算します。

・交差エントロピー誤差の逆伝播の導出

 交差エントロピー誤差を$L$とする(損失関数lossのLです)と、交差エントロピー誤差の逆伝播の入力は$\frac{\partial L}{\partial L} = 1$になります。

・ステップ1

 交差エントロピー誤差の(後から)1つ目の計算は「-1を掛ける」です。

 「$\times$」ノードの入力を$x$、出力を$y$とすると、この「-1を掛ける」は次の式になります。(この$x$と$y$はニューラルネットワークの入力・出力とは関係なく、この計算のために置いたものです。他のステップでも特に説明がなければそこだけの表記です。返って分かりにくいかもしれませんが(すみません私の表現力不足です)注意してください。)

$$ y = -1 x $$

 わざわざ書く程のことではないと思いますが、ここでの表記法に慣れる意図も込めて丁寧に書いておきます。

 $y$を$x$で微分すると

$$ \frac{\partial y}{\partial x} = -1 $$

になります。微分して$x$が1となり、係数の-1だけが残りました。
 図A-4から分かる通り、このノードの順伝播では$x$と-1が入力しています(いえしていませんね。$t_1 \log y_1 + \cdots + t_3 \log y_3$を$x$と置いたと思ってください。上の式の$x$を$t_1 \log y_1 + \cdots + t_3 \log y_3$に置き換えて、$y$を$t_1 \log y_1 + \cdots + t_3 \log y_3$で微分しても同じ-1になります)。$x$が(順)伝播(入力)してきたノードへは、他のノードから(順)伝播した-1が(逆)伝播(出力)することが分かりました。このことを「順伝播時の入力値をひっくり返した値が伝播する」と表現しています。

 従って交差エントロピー誤差の逆伝播における( (後から)1つ目の)「$\times$」ノードでは、逆伝播の入力$\frac{\partial L}{\partial L} = 1$との積

$$ \frac{\partial L}{\partial L} (-1) = - 1 $$

を次のノードに伝播します。

・ステップ2

 2つ目の計算は「総和をとる」です。

 「$+$」ノードの入力を$\mathbf{x} = (x_1, x_2, \cdots, x_{10})$、出力を$y$とすると、「総和をとる」の計算は次の式になります。

$$ \begin{aligned} y &= \sum_{k=1}^{10} x_k \\ &= x_1 + \cdots + x_k + \cdots + x_{10} \end{aligned} $$

 $y$を$k$番目の入力$x_k$で微分すると

$$ \begin{aligned} \frac{\partial y}{\partial x_k} &= 0 + \cdots + 1 + \cdots + 0 \\ &= 1 \end{aligned} $$

 $x_k$の項だけが1となり、それ以外の$x_1$から$x_{10}$は0になります。

 従って交差エントロピー誤差の逆伝播における「$+$」ノードでは、ステップ1の出力-1との積

$$ (- 1) * 1 = - 1 $$

を次のノードに伝播します。

・ステップ3

 3つ目の計算の内$k$番目の項に注目すると、その計算は「教師ラベル$t_k$を掛ける」でした。(「$k$番目の」という表現は、例えば$\mathbf{t}$であれば10個の要素の内の「ある1つの要素」という意味です。1から10のどれで合っても結果に違いは出ません。)

 「$\times$」ノードの入力を$x_k$、出力を$y_k$とすると、「$t_k$を掛ける」の計算は次の式になります。

$$ y_k = t_k x_k $$

 $y_k$を$x_k$で微分すると

$$ \frac{\partial y_k}{\partial x_k} = t_k $$

になります。

 従って交差エントロピー誤差の逆伝播における(2つ目の)「$\times$」ノードでは、ステップ2の出力-1との積

$$ -1 t_k = - t_k $$

を次のノードに伝播します。

・ステップ4

 4つ目の計算は「対数をとる」です。

 「$\log$」ノードの入力を$x$、出力を$y$とすると、「対数をとる」の計算は次の式になります。

$$ y = \log x $$

 $y$を$x$で微分すると

$$ \frac{\partial y}{\partial x} = \frac{1}{x} $$

になります。これは対数関数の微分の公式のようなものです。頭の隅に置いておいても損はないと思います(尚証明は扱い(でき)ません)。

 従って交差エントロピー誤差の逆伝播における「$\log$」ノードの入力は$y_k$なので、$\frac{1}{y_k}$とステップ3の出力との積

$$ - t_k \frac{1}{y_k} = - \frac{t_k}{y_k} $$

が交差エントロピー誤差の逆伝播の出力になります。

・「Cross Entropy Error」ノード

 4つのステップの計算をまとめて「Cross Entropy Error」ノード(レイヤ)として考えます。

 「Cross Entropy Error」レイヤの順伝播の入力を$\mathbf{y} = (y_1, y_2, \cdots, y_{10})$、教師ラベルを$\mathbf{t} = (t_1, t_2, \cdots, t_{10})$として、また逆伝播の入力を$\frac{\partial L}{\partial L}$とすると、逆伝播の出力は$\Bigl(-\frac{t_1}{y_1}, -\frac{t_2}{y_2}, \cdots, -\frac{t_{10}}{y_{10}}\Bigr)$となることが分かりました。

 この出力(値)が、Softmaxレイヤの逆伝播の入力になります。続いてSoftmaxレイヤの逆伝播を求めます。

・ソフトマックス関数の逆伝播の導出

 これまでは、計算(ノード)ごとに入力を$x$、出力を$y$と置いて微分を確認していましたが、そちらの方がややこしくなりそうなので、ここからは、本来の入力と出力の値を使って説明します。また本ではステップ1を逆伝播の入力にあてていますが、レジュメでの表記の統一のため1つ目の計算をステップ1とします。そのため本のステップとズレるので、ご注意ください(ごめんなさい)。

・ステップ1

 ソフトマックス関数の(後から)1つ目の計算は、「分子と分母を掛ける」です。

 「$\times$」ノードの順伝播の分子側の入力は$\exp(a_k)$、分母側の入力は$\frac{1}{\sum_{k=1}^{10} \exp(a_k)}$、出力は$y_k$です。よって「分子と分母を掛ける」の計算は次の式になります。(分かりにくければ$\exp(a_k)$を$x_k$、$\sum_{k=1}^{10} \exp(a_k)$を$S$と置いて考えましょう!)

$$ y_k = \frac{\exp(a_k)}{\sum_{k'=1}^{10} \exp(a_{k'})} $$


 まずは分子側のノードについて考えましょう(本でいうとステップ5の内容です)。

 $y_k$を分子側の入力$\exp(a_k)$で微分すると

$$ \frac{\partial y_k}{\partial \exp(a_k)} = \frac{1}{\sum_{k'=1}^{10} \exp(a_{k'})} $$

になります。

 従ってソフトマックス関数の逆伝播の入力$-\frac{t_k}{y_k}$との積

$$ \begin{aligned} - \frac{t_k}{y_k} \frac{1}{\sum_{k'=1}^{10} \exp(a_{k'})} &= - t_k \frac{\sum_{k'=1}^{10} \exp(a_{k'})}{\exp(a_k)} \frac{1}{\sum_{k'=1}^{10} \exp(a_{k'})} \\ &= - \frac{t_k}{\exp(a_k)} \end{aligned} $$

を分子側の次のノードに伝播します。この$y_k$はソフトマックス関数の出力なので、式(3.10)の$y_k$と同じものです。よって($y_k$は分数なので)式(3.10)の逆数で置き換えて計算しています。

 続いて分母側のノードについて考えます(本でいうとステップ2の内容です)。

 $y_k$を分母側の入力$\frac{1}{\sum_{k=1}^{10} \exp(a_k)}$で微分すると

$$ \frac{\partial y_k}{\partial \frac{1}{\sum_{k'=1}^{10} \exp(a_{k'})}} = \exp(a_k) $$

になります。

 従ってソフトマックス関数の逆伝播の入力との積

$$ \begin{aligned} - \frac{t_k}{y_k} \exp(a_k) &= t_k \frac{\sum_{k'=1}^{10} \exp(a_{k'})}{\exp(a_k)} \exp(a_k) \\ &= t_k \sum_{k'=1}^{10} \exp(a_{k'}) \end{aligned} $$

を分母側の次のノード(図の一番上のノード)に伝播します。こちらもソフトマックス関数(3.10)を用いて式を整理しています。

 色んな例で何度も確認しましたが、変数を入れ替えて伝播します!

・ステップ2

 2つ目の計算は「(1を)割る」です(本でいうとステップ3の内容です)。

 「$/$」ノードの順伝播の入力は$\sum_{k=1}^K \exp(a_k)$、出力は$\frac{1}{\sum_{k=1}^K \exp(a_k)}$です。よって「(1を)割る」の計算は次の式になります。

$$ \begin{aligned} F &= \frac{1}{\sum_{k=1}^K \exp(a_k)} \\ &= \Bigl(\sum_{k=1}^K \exp(a_k)\Bigr)^{-1} \end{aligned} $$

 ちょっと残念な表記になるのを避けるために$F$と置きます。また$\frac{1}{x} = x^{-1}$です。

 $F$を入力で微分すると

$$ \begin{aligned} \frac{\partial F}{\partial \sum_{k=1}^K \exp(a_k)} &= - 1 \Bigl(\sum_{k=1}^K \exp(a_k)\Bigr)^{-1-1} \\ &= - \frac{1}{\Bigl(\sum_{k=1}^K \exp(a_k)\Bigr)^{-2}} \end{aligned} $$

になります。

 よってステップ2の$k$番目の出力との積は

$$ - t_k \sum_{k'=1}^{10} \exp(a_{k'}) \left\{ - \frac{1}{\Bigl(\sum_{k'=1}^K \exp(a_{k'})\Bigr)^{-2}} \right\} = \frac{t_k}{\sum_{k'=1}^K \exp(a_{k'})} $$

となります。

 また図から分かるように、このノードには$k = 1$から10までの値が伝播してきます。従ってこれら全ての和

$$ \begin{aligned} \frac{\sum_{k=1}^K t_k}{\sum_{k'=1}^K \exp(a_{k'})} &= \frac{ t_1 + t_2 + \cdots + t_{10} }{ \sum_{k=1}^K \exp(a_k) } \\ &= \frac{1}{\sum_{k=1}^K \exp(a_k)} \end{aligned} $$

を次のノードに伝播します。教師ラベル$\mathbf{t} = (t_1, t_2, \cdots, t_{10})$はone-hot表現なので, 解ラベルの項が1、それ以外は0の値です。つまりその総和も1になります。

・ステップ3

 3つ目の計算は「総和をとる」です(本でいうとステップ4の内容です)。

 「$+$」ノードの順伝播の入力は$(\exp(a_1), \exp(a_2), \cdots, \exp(a_{10}))$、出力は$\sum_{k=1}^{10} \exp(a_k)$です。よって「総和をとる」の計算は次の式になります。

$$ \begin{aligned} F &= \sum_{k=1}^{10} \exp(a_k) \\ &= \exp(a_1) + \exp(a_2) + \cdots + \exp(a_{10}) \end{aligned} $$

 $F$を$k$番目のノードからの入力$a_k$で微分すると

$$ \frac{\partial F}{\partial \exp(a_k)} = 1 $$

になります。$k$番目の項$\exp(a_k)$だけが1となり、他の項は0になります。

 従って逆伝播の入力(との積)

$$ \frac{1}{\sum_{k=1}^K \exp(a_k)} $$

をそのまま次の全てのノードに伝播します。

・ステップ4

 4つ目の計算は「指数をとる」です(本でいうとステップ6の内容です)。

 「$\exp$」ノードの順伝播の$k$番目の入力は$a_k$、出力は$\exp(a_k)$です。(式にしてもそのままなので省略して、)$\exp(a_k)$を$a_k$で微分すると

$$ \frac{\partial \exp(a_k)}{\partial a_k} = \exp(a_k) $$

になります(値が変わりません)。ネイピア数の指数関数の微分$\frac{\partial \exp(x)}{\partial x} = \exp(x)$も覚えておいて損はないでしょう。

 従って、ステップ1の分子側の出力との積と、ステップ3の出力との積との和

$$ \begin{aligned} - \frac{t_k}{\exp(a_k)} \exp(a_k) + \frac{1}{\sum_{k'=1}^K \exp(a_{k'})} \exp(a_k) &= - t_k + \frac{\exp(a_k)}{\sum_{k'=1}^K \exp(a_{k'})} \\ &= y_k - t_k \end{aligned} $$

が「Softmax」ノードの逆伝播の出力になります。ソフトマックス関数の式より、$y_k$に置き換えています。

・「Softmax-with-Loss」ノード

 「Cross Entropy Error」ノードと4つのステップの計算をまとめて「Softmax-with-Loss」ノード(レイヤ)として考えます。

 「Softmax-with-Loss」レイヤの順伝播の入力を$\mathbf{a} = (a_1, a_2, \cdots, a_{10})$、出力を$\mathbf{y} = (y_1, y_2, \cdots, y_{10})$、教師ラベルを$\mathbf{t} = (t_1, t_2, \cdots, t_{10})$、逆伝播の入力を$\frac{\partial L}{\partial L} = 1$とすると、逆伝播の$k$番目の出力は$y_k - t_k$となることが分かりました。

 ここでのポイントは、順伝播の出力と教師データの差というシンプルな計算で逆伝播を求められることです!まぁこうなるように交差エントロピー誤差を定義したわけです。

・バッチデータ版「Softmax-with-Loss」ノード

 ここまでの計算は1つのデータを扱う場合でした。続いてバッチデータを扱う場合の逆伝播を考えましょう!バッチ版の交差エントロピー誤差の計算式は

$$ L = - \frac{1}{N} \sum_{i=1}^N \sum_{k=1}^{10} t_{ik} \log y_{ik} \tag{4.3} $$

でした。ここで$N$はバッチサイズです。各項の差を全てのデータ(画像)で和をとるためデータ数に応じて誤差の値が大きくなってしまうことを回避するため、バッチサイズで割ることで1データ当たりの値にするのでした。

 では最初から導出しましょう!交差エントロピー誤差における逆伝播のステップ1(「-1を掛ける」)では、-1が出力されるのでした。この値は、最終的な出力にも含まれていますね。つまりステップ1の計算を「$- \frac{1}{N}$を掛ける」とすると、同じように$- \frac{1}{N}$を(連鎖率で分解した項の)積の中の1つとして出力されます。従って、バッチデータ版のSoftmax-with-Lossレイヤの逆伝播の出力は(-1を$- \frac{1}{N}$で置き換えると)

$$ \begin{aligned} \frac{\partial L}{\partial a_{ik}} &= \frac{1}{N} y_{ik} - \frac{1}{N} t_{ik} \\ &= \frac{1}{N} ( y_{ik} - t_{ik} ) \end{aligned} $$

となります(良かった簡単に求められて)。$- \frac{1}{N}$は分母分子どちらのノードにも伝播しているため、どちらの項にも含まれています。$\frac{1}{N}$で括ると、データごとの差をデータ数$N$で割ればいいことが分かりました。

 【Pythonノート】に戻って実装しましょう!

参考文献

  • 斎藤康毅『ゼロから作るDeep Learning』オライリー・ジャパン,2016年.

おわりに

 割とすんなり導出できたので良かったです。あとここまできてやっと誤差逆伝播法という言葉の意味を理解しました!なるほど誤差を逆伝播することが目的だったのか。テキトーに読んでるから何度も何度も書き直すはめに、、

【元の記事】

www.anarchive-beta.com