はじめに
「機械学習・深層学習」学習初手『ゼロから作るDeep Learning』民のための数学攻略ノートです。『ゼロつく1』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。
NumPy関数を使って実装できてしまう計算について、数学的背景を1つずつ確認していきます。
この記事は、主に5.5.2「Sigmoidレイヤ」を補足するための内容になります。シグモイド関数の逆伝播(微分)を導出します。
【関連する記事】
【他の記事一覧】
【この記事の内容】
シグモイド関数の逆伝播
シグモイド関数を実装します。シグモイド関数は
という式でした。
この式は、シグモイド関数の入力$x$に「-1を掛ける」「指数をとる」「1を足す」「割る」の4つの計算(ステップ)に分解できます(図5-19)。この計算が順伝播であり、順伝播の出力を$y$とします。
シグモイド関数の逆伝播(微分)を求めるために、この4つの計算(シグモイド関数内)の逆伝播を確認していきます。
逆伝播の入力を$\frac{\partial L}{\partial y}$とします。また各ノード(ステップ)の入力と出力も$x$と$y$で表すので、シグモイド関数の入力・出力の話なのかに注意してください。
・ステップ1
シグモイド関数の(後から)1つ目の計算は、入力で「割る」です。
「/」ノードの入力を$x$、出力を$y$とすると、「入力で割る」の計算は次の式になります。
この$x$はあくまで割り算ノードの入力のことで、シグモイド関数の入力$x$のことではないので注意してください。
分数はマイナスの指数を使って$\frac{1}{x} = x^{-1}$と表すことができます。つまりこの「入力で割る」の式は、次のように書き換えられます。
この書き方だと微分の公式に当てはめやすいですよね。
この式を$x$で微分すると
となります。
この計算結果でもいいですが、少し変形しておきます。最初の式の両辺を2乗すると$y^2 = (\frac{1}{x})^2 = \frac{1}{x^2}$なので、この式に代入すると、「/」ノードの微分は
順伝播の出力の2乗にマイナスを付けた値になります。
さて図5-19から分かる通り、シグモイド関数における「$/$」ノードの順伝播の入力は$1 + \exp(x)$ですね。最初の式では、この$1 + \exp(x)$を$x$と置いて考えたともいえます(分かりにくければ$x'$とすればいいです)。またこのノードは最後のノードなので、このノードの順伝播の出力はシグモイド関数の順伝播の出力と同じものです($y$という文字が同じなのはたまたまの部類です)。つまり(シグモイド関数の順伝播の出力)$y$に対する(シグモイド関数の順伝播の入力)$1 + \exp(x)$の微分も$- y^2$となります。(ちなみに$1 + \exp(-x)$のマイナスの2乗のマイナスだと扱いづらいので、$- y^2$に置き換えました。またこれが最後に便利に働きます(お楽しみに!)。)
従ってシグモイド関数の逆伝播における「/」ノードでは、逆伝播の入力$\frac{\partial L}{\partial y}$との積
を次のノードに伝播します。
・ステップ2
2つ目の計算は、入力に「1を足す」です。
「+」ノードは微分すると1になるので、上流の値をそのまま下流に流すのでした(5.3.1項)。一応復習もかねて、式にして確認しておきましょう。「+」ノードの入力を$x$、出力を「$y$」とすると「1を足す」の計算式は
ですね。
この式を$x$で微分すると
になります。ちなみに$x^0 = 1$です。これは入力の値に関わらず1になるということです。
従ってシグモイド関数の逆伝播における「+」ノードでは、ステップ1の出力
をそのまま(1を掛けて)次のノードに伝播します。
・ステップ3
3つ目の計算は、入力の「指数をとる」です。
「$\exp$」ノードの入力を$x$、出力を$y$とすると、「指数をとる」の計算は次の式になります。
この式を$x$で微分すると
となります。$\exp(\cdot)$は、微分してもそのままの値になるという性質を持っています。(これはネイピア数の指数関数$y = \exp(x)$の傾きが$\exp(x)$であるということです。)
従ってシグモイド関数の順伝播における「$\exp$」ノードの入力は$-x$なので、$\exp(-x)$とステップ2の出力との積
を次のノードに伝播します。
・ステップ4
4つ目の計算は、入力に「-1を掛ける」です。
「$\times$」ノードでは、順伝播時の値をひっくり返して乗算でした(5.3.2項)。ここまできたらこれも丁寧に復習しておきたいですよね。ということで「$\times$」ノードの入力を$x$、出力を$y$としたら計算式は
です。
この式を$x$で微分すると
となります。
従ってシグモイド関数の逆伝播における「$\exp$」ノードでは、(順伝播の入力値が何であれ)-1とステップ3の出力との積
が「Sigmoid」ノードの出力となります。
・「Sigmoid」ノード
シグモイド関数を構成する4つの計算(ノード)の微分が求まりました。この4つの値と逆伝播の入力(ここでは$\frac{\partial L}{\partial y}$とします)の積
が、「Sigmoid」ノードの逆伝播の出力となります。
(少しだけ整理しましたが)このままだとゴチャゴチャしていて、計算するのが(あと理解するのも書くのも)手間ですよね?なのでこの式を整理してみましょう!
まず($y^2 = y * y$の片方に)シグモイド関数の式(5.9)を代入すると
となりますね。これをちょっと工夫する(分子に$1 - 1 = 0$を足す)と
となります。1行目から2行目の変形は、$1 + \exp(-x)$を$A$とでも置けば$\frac{A - 1}{A}$を$\frac{A}{A} - \frac{1}{A}$に分解しているだけです。
最後にもう一度、式(5.9)を使って$y$に戻すと
はいっできました!
シグモイド関数の微分が$y (1- y)$という非常に簡単な計算になりました。
変形したこの式のポイントは、「シグモイド関数の逆伝播の入力と順伝播の出力$y$を使った簡単な計算とで、逆伝播を計算できてしまう!」ことです。
では【実装ノート】に戻って、Sigmoidレイヤを実装しましょう。
参考文献
- 斎藤康毅『ゼロから作るDeep Learning』オライリー・ジャパン,2016年.
おわりに
詳しく書き忘れたのですが、ノードごとの微分の積が全体の微分になります。これが連鎖率による分解に対応しています(というかそのものです)。あとノードとレイヤの区別も適当な気がします。1つずつの計算がノードで、同列の計算(ノード)をひとまとめにしてレイヤと呼んでます。$a_k$に対してはシグモイド関数ノードで、$\mathbf{a} = (a_1, \cdots, a_M)$に対してはシグモイド関数レイヤと言い分けて(いたりいなかったりしてると思)います。
これは言い訳なのですが、今回は順番通りに書かなかったので色々統一感に欠けてます(何なら連鎖率の節は最後に書いています(まだ完成していません) )。すみません…
【元の記事】
2020年8月1日:「ハロー!プロジェクト」&「アンジュルム」元リーダー和田彩花さんのお誕生日!
おめでとうございます!!!