ニューラルネットワークを勉強したので、それを自分なりにまとめた備忘録。初学者なのでお手柔らかに。深層学習 改訂第二版(岡谷貴之)・絶対に理解させる誤差逆伝播法(ヨビノリ)を用いて学習した。
ニューラルネットワーク基本原理
ニューラルネットワーク(NN)は、いくつかの入力データを統合し、活性化関数をかけて出力するという構造を持っている。その統合の度合いを学習によって最適化するというのが基本原理となる
具体的なフローとしては、
①入力データ群に初期重みを付けて足し合わせる $u=w_1x_1+w_2x_2+...+b$($b$はバイアス)
②その合計値に活性化関数と呼ばれる非線形関数を演算する $y=f(u)$
③正解データとの誤差(損失関数)を比較する $(y-d)^2$
というフローになっている。
ここで、活性化関数を演算する理由としては、活性化関数なしだと入力データの線形演算となってしまい、非線形な関数を表現することができないからである。非線形性の担保として活性化関数は存在すると考えてもらえればよい。
活性化関数としてよくあるのが、ソフトマックス関数
$y_k = \frac{\exp(a_k)}{\sum_{i=1}^{K} \exp(a_i)}$
である。これは、合計値が1になるのが嬉しいところで、出力に確率の意味を持たせたい際によく利用される。指数関数を噛ませている分、普通の正規化より、値の差に敏感であり、各出力の差を広げたいような場面(ex.この画像は確率$p$で犬であり、確率$1-p$で猫であると判断する課題)で重宝される。
損失関数としてよくあるのは、最小二乗誤差
$E(w) = \frac{1}{2}\sum_{i=1}^{N}(y_i - d_i)^2$
である。
損失関数、つまり学習データとの差をできるだけ小さくするように重み$w$を更新していく。つまり、損失関数を$w$で偏微分し、損失関数を最小化する方向に$w$を変化させていく。
最小化する手法の一つとして、勾配降下法が存在する。勾配降下法の原理については下で記載しよう。
ニューラルネットワーク(NN)を学習する際に誤差逆伝播法で躓く人間は多いと思うが、思うに、誤差逆伝播は本質ではなく、本質は以上で説明した部分にある。誤差逆伝播は、上記の偏微分を効率よく行うための計算方法の一種であり、NNの原理に直接寄与するものではない。
ただ、NNの設計に当たって誤差逆伝播を避けて通ることは非常に難しいのでその原理も記しておく。
以上でNNの基本的な流れを定性的に抑えた。以下では、説明した原理を定量的に記していく。
なお、正則化や、損失関数の種類・活性化関数の種類についてはまだ理解が追い付いていない部分も存在するので別の記事で記載しようと思う。
よく使う用語の定義
ユニット:ニューラルネットワークを構成する最小要素。入力を重み付き和し、活性化関数を演算する一連のノードのこと。
エポック:学習データをすべて使いきる(一巡する)こと
バリデーションデータ:学習中のモデル性能を評価するためのデータ
ミニバッチ:いくつかのサンプルをひとまとまりにして重み計算を行う
さて、定量的説明に進もう。
勾配降下法
損失関数(出力データと正解データとの誤差)を最小化したいというのはわかったが、じゃあどうやって最小化するのだ?というのが勾配降下法である。
まず前提として、最小化といっても基本的にNNは局所解しか得られないことに留意する。ただ、その極小点での損失がある程度小さければ問題ないとする立場である。
まず、勾配とは、各データにおける損失関数の合計をパラメータで一次微分したもので、
$$
\nabla E=\frac{\partial E}{\partial w}=
\begin{pmatrix}
\frac{\partial E}{\partial w_1}\
\frac{\partial E}{\partial w_2}
\end{pmatrix}
$$
と表される。一回の更新で重みを$w_t$から$w_{t+1}$に更新する。その更新式は
$$w_{t+1}=w_t-\epsilon \nabla E$$
である。ここで$\epsilon$は学習率と呼ばれる。
勾配降下法は数ある非線形関数の最小化方法の中で単純なものである。ニュートン法のような、損失関数の二次微分を利用するものと比較すると極小解への収束速度が遅いという課題が存在する。一方で、パラメータ数が多すぎて一次微分までしか計算量的に行えないような場合については、勾配降下法が用いられる。
これの発展形として、確率的勾配降下法(SGD)が存在する。勾配降下法は$\sum_{n=1}^N{E_n(w)}$のように、各訓練データの損失関数の総和を用いていたが、SGDは各訓練データからランダムに損失関数を一つ選び、それを用いて重みを更新する。ランダム性があるから確率的勾配降下法である。反復のたびに異なる損失関数を用いるため、よくない局所解に陥る確率が下がり、計算量も少ないという利点が存在する。
モメンタム
ここで、モメンタムという手法も紹介しておこう。
SGDでは、パラメータの更新ごとに異なる目的関数を使用するので不安定であるという課題が存在する。それを解消するのがモメンタムである。これは、重みの修正量に、前回の重みの修正量の何割かを加算することで安定化を図る手法である。学習率が高すぎて極小解を超えてしまったような際(つまり学習の方向がtとt+1で反転してしまったような際)に、自動的に戻してくれる役割を果たす。モメンタムは、ほとんどのSGDで用いられる手法である。
Adam
以上を読み気づいた方もいると思うが、SGDは学習率がユーザーが調整できるパラメータである。そして、結構学習率ゲーなのである。学習率がいい感じであれば上手くいくし、良くないと上手くいかない。従って、学習率を時間変化させる(初めは大きく、だんだん小さく等)手法がよく用いられる。
それと同時に、学習率の初期値の重要度を下げる取り組みも行われている。その一例としてAdaGrad、Adamを紹介しておく。
まず、AdaGradは、学習率を、今までの勾配の二乗で割った形に更新していく手法である。これにより、前回の更新で勾配が大きかったものについては小さく更新し、勾配が小さかったものについては大きく更新するという計算を行うことができる。
Adamとは、AdaGradにモメンタムを導入したものである。
誤差逆伝播法
さて、最も躓きやすいであろう誤差逆伝播法について解説していく。
誤差逆伝播法というのは、勾配降下法にて用いた、誤差関数の重みでの偏微分というのが計算として煩雑すぎるため使用される手法である。
なぜなら、$E_n=\frac{1}{2}|y(x_n)-d_n|^2$なる損失関数を第$l$層の重みで偏微分しようとすると、第$l$層の重みを$W^{(l)}_n$とし、$l$層の出力を$z^{(l)}_n$とすれば(なお、$z^{(0)}_n=x_n$であり、$z^{(L)}_n=y_n$)
$$
y(x_n)=f(u^{(L)}_n)=f(W^{(L)}z^{(L-1)}+b^{(L)})=...
$$
のように、層をさかのぼる必要があるからである。この計算を簡略化するのが誤差逆伝播法である。
まず、なぜ逆に伝播するのかについて説明する。

上図に示されるような重みを修正していくのだが、前半部分の重みを修正すると、後半部分の重みに影響が出ることは、図を見れば直感的に理解できるだろう。従って、2層目の情報を使用せずに1層目の最適化を行うことはできない。逆に、2層目(今回の例では最深層)は、他の情報を一切使用せずに最適化を行うことが可能である。よって、深い層から逆伝播する形で最適化を行う必要がある。
連鎖律
誤差逆伝播法に入る前に連鎖律について学ぶ。
連鎖律とは、多変数関数の偏微分の法則である。
$$z=f(u_1,u_2,...)$$
のような関数があり、$u_k$は$x$の関数であるとする。この時の$\frac{\partial z}{\partial x}$はどのように求められるのかという問題である。
まず一変数の際($z=f(u)$の場合)は、$\frac{\partial z}{\partial x}=\frac{\partial z}{\partial u}\frac{\partial u}{\partial x}$となることは既知として進める。これがわかれば多変数でも同様で、偏微分というのは、ある変数を動かしたときにどの程度目的関数の値が変動するかという指標なので、多変数の場合全ての変数の合計値となり
$$
\frac{\partial z}{\partial x}=\frac{\partial z}{\partial u_1}\frac{\partial u_1}{\partial x}+\frac{\partial z}{\partial u_2}\frac{\partial u_2}{\partial x}+...
$$
となる。
誤差逆伝播法再訪
前提知識の共有も終わったところで誤差逆伝播法に戻る。
以下の図を見てほしい。第$l$層に入る全ての入力の線形和を$u^{(l)}_j$とし、それに活性化関数をかけたものを$z^{(l)}_j$
とする。そして、$l-1$層の$i$番目のユニットから$l$層の$j$番目のユニットへの重みを、$W^{(l)}_{i,j}$としよう。

簡便に計算できることを数学的帰納法で証明していこう。ここでいう簡便というのは、学習データとなる入力を入れて出力が出るまでの間に勝手に計算される$u_j$や$z_j$のような値を用いて計算することができるということをさす。それが実現すれば、これらの値を保持するだけで高速で計算が可能である。
まず最深部である出力層について、各重みによる損失関数の偏微分を行うと、
$$
\frac{\partial E}{\partial W^{(L)}_{i,j}}=\frac{\partial E}{\partial z^{L}_j}\frac{\partial z^{L}_j}{\partial W^{(L)}_{i,j}}
$$
ここで$\frac{\partial E}{\partial z^{L}_j}$は、$z^{(L)}_j$が$y_j$であることを鑑みるに計算可能であり、$\frac{\partial z^{L}_j}{\partial W^{L}_{i,j}}$は、$u^{(L)}_j$まで偏微分を変形すれば計算可能である。よって、最深部では$\frac{\partial E}{\partial W^{(L)}_{i,j}}$の計算が可能であることが分かった。
次に、一般的な第$l$層での計算を考える。
$$
\frac{\partial E}{\partial W^{(l)}_{i,j}}=\frac{\partial E}{\partial z^{l}_j}\frac{\partial z^{l}_j}{\partial W^{(l)}_i,j}
$$
ここで、$\frac{\partial E}{\partial z^{l}_j}=\frac{\partial E}{\partial u^{l}_j}\frac{\partial u^{l}_j}{\partial z^{l}_j}$であり、$\frac{\partial u^{l}_j}{\partial z^{l}_j}=\frac{d{f^{(l)}(z_j)}^{-1}}{dz^{(l)}_j}$であるから、これは計算可能。$\frac{\partial E}{\partial u^{l}_j}$については一旦$\delta^{(l)}_j$と置く。
そして、$\frac{\partial z^{l}_j}{\partial W^{(l)}_{i,j}}$については、変形して$\frac{\partial z^{l}_j}{\partial W^{(l)}_{i,j}}=\frac{\partial z^{l}_j}{\partial u^{l}_j}\frac{\partial u^{l}_j}{\partial W^{(l)}_{i,j}}$とすれば、最深部と同様に計算可能である。
以上をすべての層に適用することで、損失関数の重みでの偏微分を実現するのがが誤差逆伝播法である。
さて、以上で一般的なNNの解説はできたので、次回以降はCNN、RNNなどの解説を行おうと思います。