Coursera機械学習の第5週目ではニューラルネットワークモデルによって実際に問題を解く方法について説明されております。
ここでいわゆるバックプロパゲーション(もしくは誤差逆伝播法)が登場しますが、講座では、理論よりも実践(プログラム)でどのように実装するかといった点に重きを置いています。
よって本記事でも、ニューラルネットワークを使う事に重点を置いたまとめ方をしていきたいと思います。
※なお説明がない添字、変数については、第4週の記事をご参照ください。
バックプロパゲーション
ロジスティック回帰で、最急降下法、もしくはより高度なBFGS法などにおいて、$\theta$を求めるのに必要なのは目的関数 $J(\theta)$ と勾配 $\nabla J(\theta)$ でした。
ニューラルネットワークでも同様で、目的関数と「各層・各ユニット」の勾配を求める事により「各層・各ユニット」の$\Theta$を求められます。
ニューラルネットワークの場合の目的関数は以下です。
$$J(\Theta) = – \frac{1}{m} \sum_{t=1}^m\sum_{k=1}^K \left[ y^{(t)}_k \ \log (h_\Theta (x^{(t)}))_k + (1 – y^{(t)}_k)\ \log (1 – h_\Theta(x^{(t)})_k)\right] + \frac{\lambda}{2m}\sum_{l=1}^{L-1} \sum_{i=1}^{s_l} \sum_{j=1}^{s_{l+1}} ( \Theta_{j,i}^{(l)})^2$$
ここで$t$は教師データの添字、$k$は分類するクラス数の添字です。
なお、これまでの受講記では、目的関数の数式には行列表現を使用していたので、上記のような添字+総和の記号は使ってきませんでしたが、第5週では、教師データについて行列で計算するのではなくループ処理で実装する事を奨励しているため、以降、添字表現で式を記載します。
行列で計算できないわけではないですが、おそらく初心者が理解しやすいように、そうしているのだと思います。(なお、同じ先生が開講しているディープラーニングの講座では、普通に行列表現を使っています。)
目的関数から勾配を求めるわけですが、各層・ユニットの勾配・・つまり$\dfrac{\partial J(\Theta)}{\partial \Theta_{i,j}^{(l)}}$を求めるために偏微分のチェインルールにより$h_\theta (x^{(t)})$からさかのぼっていき求めることになります。(これがバックプロパゲーションの名前の由来です。)
この言葉だけだとわかりにくいですが・・本講座では、理論よりも実践を重要視しているので、ここでも、あまり詳しく説明しないで結果のみを記載します。
\begin{eqnarray}
\dfrac{\partial J(\Theta)}{\partial \Theta_{i,j}^{(l)}} &=& \frac{1}{m}\left(\sum_{t=1}^m a_j^{(t)(l)} {\delta}_i^{(t)(l+1)} + \lambda\Theta^{(l)}_{i,j}\right)&\qquad (j\not=0\text{の場合})\\
\dfrac{\partial J(\Theta)}{\partial \Theta_{i,j}^{(l)}} &=& \frac{1}{m}\left(\sum_{t=1}^m a_j^{(t)(l)} {\delta}_i^{(t)(l+1)} \right)&\qquad (j=0\text{の場合})
\end{eqnarray}
ここで$\delta_j^{(t)(l)}$は「誤差」で、下記のように出力層からさかのぼって求められます。
\begin{eqnarray}
\delta_i^{(t)(L)}&=&a_i^{(L)}-y^{(t)}\\
\delta_j^{(t)(l)}&=&\sum_{i=1}^{s_{l+1}} ( \Theta_{j,i}^{(l)}\delta_i^{(l+1)} ) a_j^{(t)(l)}(1 – a_j^{(t)(l)})\qquad (l=L-1,L-2,\cdots,2)
\end{eqnarray}
出力層の誤差($\delta_i^{(t)(L)}$)は、モデルの出力値($a_i^{(L)}$)と実際の値($a_i^{(L)}$)の差になっており、その誤差が逆伝搬していくイメージです。
計算チェック
第5週目は実践に力を入れているので、実装したコードをチェックする方法が紹介されています。
簡単に言ってしまうと、微分を近似的な差分を比較して、ほぼ同じ値になるかを調べる方法になります。
$$\dfrac{\partial}{\partial\Theta_j}J(\Theta) \approx \dfrac{J(\Theta_1, \dots, \Theta_j + \epsilon, \dots, \Theta_n) – J(\Theta_1, \dots, \Theta_j – \epsilon, \dots, \Theta_n)}{2\epsilon}$$
ここで$\epsilon$は、なるべく小さい値がよく、具体的な値としては$\epsilon = 10^{-4}$が推奨されています。
初期値の選択について
普通のロジスティック回帰では、$\theta$の初期値は0でOKでしたが、ニューラルネットワークで各$\Theta_{i,j}^{(l)}$の初期値を0にしてしまうと、同じ層の各ユニットが全部、同じ値に収束してしまうので、違う値を選ぶ必要があります。
具体的には、$\Theta_{i,j}^{(l)}$は、以下の式で定義される$\epsilon$により$[-\epsilon,\epsilon]$の間の乱数値で初期化します。
$$\epsilon = \dfrac{\sqrt{6}}{\sqrt{\mathrm{Loutput} + \mathrm{Linput}}}\qquad (\mathrm{Linput}\text{は}l\text{層のユニット数},\mathrm{Loutput}\text{は}l+1\text{層のユニット数})$$
「なんで、この値にするの?」ってのは、以下のリンク先に載っているようです。(すいません、私は読んでません。ちなみに英語です。)
https://web.stanford.edu/class/ee373b/nninitialization.pdf
まとめ
以上、第5週のニューラルネットワークの受講記でした。
肝心のバックプロパゲーションの部分ですが、とりあえず使う事に重点を置いているので、あまり「どうして、勾配がその値になるのか」という理論には重きを置いてません。
まあ、個人的にはもうちょっと突っ込んで説明してくれてもいいかなと思いました。
因みに、同じ先生の別の講座(https://www.coursera.org/learn/neural-networks-deep-learning)では、かなり細かく説明されています。