誤差逆伝播法の公式を並べておこうと思う(特にN個のデータをバッチ形式で入力する際の公式).
初心者がニューラルネットワークを実装する際に気をつけておきたいことは,逆伝播では順伝播の値をキャッシュする必要があるということである.
順伝播
どのlayerも input
次元(ベクトル)の入力xを線形変換で output
次元の変数zに変換し,その各要素を非線形な関数 f
で output
次元yとして出力する.プログラミング言語で実装する際は,このlayerオブジェクトにxとzの値をキャッシュさせておく必要がある.
$$\begin{align*} \boldsymbol{x} \in \mathbb{R}^{\mathrm{input}} \longrightarrow \boldsymbol{z} = W \boldsymbol{x} + \boldsymbol{b} \in \mathbb{R}^{\mathrm{output}} \longrightarrow \boldsymbol{y} = f(\boldsymbol{z}) \in \mathbb{R}^{\mathrm{output}} \end{align*}$$
ここの行列変数Wとバイアスbはlayerオブジェクトの変数であり,これが勾配法(SGD, Adam, AdaGradなど)で更新されていく.
またxをベクトルではなく,N回分のデータをまとめたバッチ形式 $\boldsymbol{x} = [\boldsymbol{x}_1 \boldsymbol{x}_2 \cdots \boldsymbol{x}_N]$ で入力することがある.その場合zとyも同様に横にベクトルを並べるので行列になるが,上の式はそのまま適用できる.
これが最終層まで適用され,その出力と目標値から損失の勾配 $\partial E / \partial \boldsymbol{y}$ が求められる.
逆伝播
最終層の出力を $\boldsymbol{y}$ ,その目標値を $\boldsymbol{t}$ とすると,損失関数 $E$ の $\boldsymbol{y}$ に関する勾配は回帰でも分類でも(よく使われる損失関数については) $\boldsymbol{y} - \boldsymbol{t}$ となる.この $\partial E / \partial \boldsymbol{y} = \boldsymbol{y} - \boldsymbol{t}$ を起点に諸々の勾配を求めていく.
$$\begin{align*} \dfrac{\partial E}{\partial \boldsymbol{z}} &= \dfrac{\partial E}{\partial \boldsymbol{y}} \odot f^{\prime}(\boldsymbol{z}) = \left[ \dfrac{\partial E}{\partial \boldsymbol{z}_1}, \dfrac{\partial E}{\partial \boldsymbol{z}_2}, \cdots, \dfrac{\partial E}{\partial \boldsymbol{z}_N} \right] \in \mathbb{R}^{\mathrm{output}} \\ \dfrac{\partial E}{\partial W} &= \dfrac{\partial E}{\partial \boldsymbol{z}} \boldsymbol{x}^{\text{T}} \in \mathbb{R}^{\mathrm{output}} \times \mathbb{R}^{\mathrm{input}} \\ \dfrac{\partial E}{\partial \boldsymbol{b}} &= \sum_{i} \dfrac{\partial E}{\partial \boldsymbol{z}_i} \in \mathbb{R}^{\mathrm{output}} \\ \dfrac{\partial E}{\partial \boldsymbol{x}} &= \boldsymbol{W}^{\text{T}} f^{\prime}(\boldsymbol{z}) \in \mathbb{R}^{\mathrm{input}} \end{align*}$$
ここで $\odot$ は要素ごとの積である.また順伝播での値xとzを用いていることに注意.
そして4つ目の $\partial E / \partial \boldsymbol{x}$ が 次のlayerにとっての $\partial E / \partial \boldsymbol{y}$ となるので,そこでも上の公式で各変数の勾配を求められる.このようにして,一番最初の入力についての $$\partial E / \partial \boldsymbol{x}$$ までが全て求まる.
オプティマイザー
逆伝播では上の公式で各変数の勾配を求めたあと変数の更新を行い,次のlayerへ移る.勾配法にも以下のようにいくつかの種類がある.
ここで $\boldsymbol{w}_t$ などは行列変数Wまたはバイアスbである(演算は全て要素ごととする).
SGD
学習率 $\eta$ を勾配 $\boldsymbol{g}_t$ に乗じて学習勾配 $\Delta \boldsymbol{w}_t$ とし,現在の値からそれを減じる.
$$\begin{align*} \boldsymbol{g}_t &= \nabla E(\boldsymbol{w}_t) \\ \Delta \boldsymbol{w}_t &= -\eta \boldsymbol{g}_t \\ \boldsymbol{w}_{t+1} &= \boldsymbol{w}_t + \Delta \boldsymbol{w}_t \end{align*}$$
Momentum SGD
以前の学習勾配 $\Delta \boldsymbol{w}_{t-1}$ を用いる.この値はlayerかfunctionにメンバ変数としてキャッシュしておく必要がある.
$$\begin{align*} \boldsymbol{g}_t &= \nabla E(\boldsymbol{w}_t) \\ \Delta \boldsymbol{w}_t &= \mu \Delta \boldsymbol{w}_{t-1} - (1 - \mu) \eta \boldsymbol{g}_t \\ \boldsymbol{w}_{t+1} &= \boldsymbol{w}_t + \Delta \boldsymbol{w}_t \end{align*}$$
RMSProp
$$\begin{align*} \boldsymbol{g}_t &= \nabla E(\boldsymbol{w}_t) \\ \boldsymbol{v}_t &= \rho \boldsymbol{v}_{t-1} + (1 - \rho) \boldsymbol{g}^{2}_{t} \\ \Delta \boldsymbol{w}_t &= -\dfrac{\eta}{\sqrt{\boldsymbol{v}_t + \epsilon}} \boldsymbol{g}_t \\ \boldsymbol{w}_{t+1} &= \boldsymbol{w}_t + \Delta \boldsymbol{w}_t \end{align*}$$
パラメータ $\boldsymbol{v}_t$ の以前の値をキャッシュしておく必要がある.
Adam
$$\begin{align*} \boldsymbol{g}_t &= \nabla E(\boldsymbol{w}_t) \\ \boldsymbol{m}_t &= \rho_1 \boldsymbol{m}_{t-1} + (1 - \rho_1) \boldsymbol{g}_{t} \\ \boldsymbol{v}_t &= \rho_2 \boldsymbol{v}_{t-1} + (1 - \rho_2) \boldsymbol{g}^{2}_{t} \\ \hat{\boldsymbol{m}}_t &= \dfrac{\boldsymbol{m}_t}{1 - \rho_1} \\ \hat{\boldsymbol{v}}_t &= \dfrac{\boldsymbol{v}_t}{1 - \rho_2} \\ \Delta \boldsymbol{w}_t &= -\dfrac{\eta}{\sqrt{\hat{\boldsymbol{v}}_t + \epsilon}} \hat{\boldsymbol{m}}_t \\ \boldsymbol{w}_{t+1} &= \boldsymbol{w}_t + \Delta \boldsymbol{w}_t \end{align*}$$
パラメータ $\boldsymbol{m}_t, \boldsymbol{v}_t$ の以前の値をキャッシュしておく必要がある.