Change before you have to.

androidアプリ開発、iosアプリ開発、rails、deep learning .etc.を使った社会実験。

無性に機械学習がしたくてdeep learningをアプリに実装してみた話③

前回寄り道をしてしまいましたが、

今回は実装してみたシリーズ第三弾です。

 

第二弾では、ニューラルネットワークの中間層から出力層への接続荷重の更新をやりましたが、

今回は宣言したように、ニューラルネットワークにおける入力層から中間層への接続荷重の更新を行います。

 

接続荷重の更新は前回紹介したように、出力信号と教師信号の誤差Eの自乗が最低値となるように更新すべきなので、

 

 { \displaystyle \frac{\partial E}{\partial W_{i, j}} = 0}

 

となる{ \displaystyle W_{i,j}}になるように更新していきます。

 

今回は評価関数Eを以下のように分解します。

 

 

{ \displaystyle \frac{\partial E}{\partial W_{i, j}} = \sum_{{k'}=0}^{max_k} (\frac{\partial E}{\partial output_{k'}} \frac{\partial output_{k'}}{u_{k'}} \frac{\partial u_{k'}}{\partial hidden_j}) \frac{\partial hidden_j}{\partial u_j} \frac{\partial u_j}{\partial W_{i,j}} }

 

ここで{u_k}は出力層の細胞kの内部状態、{u_j}は中間層jの細胞の内部状態としています。

なぜこのような形になっているのか...それは微分しやすくするためです。( ! )

 

右辺の積は以下のように、 

{ \displaystyle \frac{\partial u_{k}}{\partial h_{j}} = \frac{\partial }{\partial h_j} \sum_{j'=0}^{{max}_j} hidden_{j'} \cdot W_{j',k} = W_{j,k} }

 

{ \displaystyle \frac{\partial hidden_j}{\partial u_j} = \frac{\partial }{\partial u_j} \frac{1}{1+ e^{-au_j} } =  \frac{-ae^{-au_j}}{1+e^{-au_j}} = a \cdot (1-output_j) \cdot output_j }

 

{ \displaystyle \frac{\partial u_{j}}{\partial W_{i,j}} = \frac{\partial }{\partial W_{i,j}} \sum_{i'=0}^{{max}_i} input_{i'} \cdot W_{i',j} = input_{i} } 

 

 となるので、結局、

 { \displaystyle ΔW_{i,j} = -δ \left\{ \sum_{j'=0}^{{max}_j} (output_k-supervisor_k) \cdot output_k \cdot (1-output_k) \cdot W_{h,k} \right\} hidden_j \cdot (1-hidden_j) \cdot input_i}

 

が最終形になります。

 

このΔWijを入力層のi番目のニューロンから中間層j番目のニューロンへの接続荷重に加えてあげれば良いです。

 

 

こうして、前回の中間層から出力層への接続荷重と、

今回の入力層から中間層への接続荷重に対して
それぞれ変化量ΔWj,k、ΔWi,jを計算し、加えてあげることで誤差Eが低下します。
すなわち、学習が進む、ということになります。

計算過程は偏微分と全微分の大学一年生で習う数学の公式を使って

ひたすらぐるぐる計算しているのですが、
これらの計算を覚える必要はなくて、

最後の結果だけを適用すれば良いです。

 

接続荷重の更新の中で、δという文字が出てきますが、

これは0〜1の間の小数で表される学習の効率性を示します。


効率性だからといって大きな値にしてはいけません。
ニューラルネットの接続荷重は初期状態においてランダムで、

いわば赤ちゃんが意味のある言葉を喋られないように、
初期の出力ニューロンは無意味な値を出力します。
学習が進むにつれてこのランダムな出力は試行錯誤を繰り返しながら、

接続荷重が雑然とした状態から徐々に自己組織的に正しい(?)値に近づき

出力ニューロンが教えられた通りの出力を示します。


この試行錯誤の部分において、どれだけ冒険していいか、

また冒険した結果、どれだけ自分自身の接続荷重を更新していいかを

決める指標にもなるため、あまりにも大きい値をとってしまうと

接続荷重の変化量がふりきれてしまい、

思うように学習が進まないということがあります。

また一方で、あまりにも小さい値にしてしまうと、学習の進捗が遅くなってしまいます。 

 

ニューロン数や(中間層を増やす場合は)層数によって適当な値は異なりますが 

ニューラルネットワークには他にもシグモイド関数の勾配(式中ではa)など

無数のパラメータが存在しています。

実際の脳ではこれらのパラメータでさえ、接続荷重と同様に学習して変化しているとも言われています。

これら無数のパラメータの調整が学習の難しさにも繋がっているのですが、

ニューラルネットワークの規模や形態によって適切な値に変更してあげる必要があります。

 

次回では、実際に実装した結果を示したいと思います。

また上記パラメータ調整による学習スピードの変化についても調べる予定です。