いものやま。

雑多な知識の寄せ集め

ニューラルネットワークについて学んでみた。(その4)

昨日は多層ネットワークの学習方法について説明した。

今日は多層ネットワークの学習で必要になる、勾配計算について。

勾配の計算

まず、入力  \boldsymbol{x} \in \mathbb{R}^{J_1} に対する出力  \boldsymbol{y} \in \mathbb{R}^{J_L} を得るために、次のように入力層から出力層に向かって、各層の出力  \boldsymbol{z}^{(l)} \in \mathbb{R}^{J_l} を順番に計算していくとする:

  1.  l = 1 について、 \boldsymbol{z}^{(1)} = \boldsymbol{x}
  2.  l = 2, \cdots , L について、
    •  u^{(l)}_j = \boldsymbol{w}^{(l)}_j {}^{\mathrm{T}} \boldsymbol{z}^{(l-1)} + b^{(l)}_j
    •  z^{(l)}_j = f^{(l)} ( u^{(l)}_j )
  3.  l = L について、 \boldsymbol{y} = \boldsymbol{z}^{(L)}

このとき、この入力に対する誤差の勾配  \nabla E がどうなるのかを考える。

まず、出力層の重み  \boldsymbol{w}^{(L)}_j = (w^{(L)}_{j,1}, \cdots , w^{(L)}_{j, J_{L-1}} )^{\mathrm{T}} について偏微分を考えると、

 {\displaystyle
\begin{align}
\frac{ \partial E }{ \partial w^{(L)}_{j, i} } &= \frac{ \partial E }{ \partial u^{(L)}_j } \frac{ \partial u^{(L)}_j }{ \partial w^{(L)}_{j, i} } \\
&= \frac{ \partial E }{ \partial u^{(L)}_j } z^{(L-1)}_i
\end{align}
}

また、出力層のバイアス  b^{(L)}_j についての偏微分は、バイアスを入力が常に1である重みであるとみなすと、次のようになる:

 {\displaystyle
\frac{ \partial E }{ \partial b^{(L)}_j } = \frac{ \partial E }{ \partial u^{(L)}_j }
}

そして、中間層  l = 2, \cdots , L -1 の重み  \boldsymbol{w}^{(l)}_j = (w^{(l)}_{j,1}, \cdots , w^{(l)}_{j, J_{l-1}} )^{\mathrm{T}} について偏微分を考えると、

 {\displaystyle
\begin{align}
\frac{ \partial E }{ \partial w^{(l)}_{j, i} } &= \frac{ \partial E }{ \partial u^{(l)}_j } \frac{ \partial u^{(l)}_j }{ \partial w^{(l)}_{j, i} } \\
&= \frac{ \partial E }{ \partial u^{(l)}_j } z^{(l-1)}_i \\ 
&= \left( \sum_{k=1}^{J_{l+1}} \frac{ \partial E }{ \partial u^{(l+1)}_k } \frac{ \partial u^{(l+1)}_k }{ \partial u^{(l)}_j } \right) \: z^{(l-1)}_i
\end{align}
}

ここで、

 {\displaystyle
\begin{align}
u^{(l+1)}_k &= \sum_{j=1}^{J_l} w^{(l+1)}_{k, j} z^{(l)}_j  \\
&= \sum_{j=1}^{J_l} w^{(l+1)}_{k, j} f^{(l)} ( u^{(l)}_j )
\end{align}
}

なので、

 {\displaystyle
\frac{ \partial u^{(l+1)}_k }{ \partial u^{(l)}_j } = w^{(l+1)}_{k, j} {f^{(l)}}' ( u^{(l)}_j )
}

となることから、

 {\displaystyle
\begin{align}
\frac{ \partial E }{ \partial w^{(l)}_{j, i} } &= \left( \sum_{k=1}^{J_{l+1}} \frac{ \partial E }{ \partial u^{(l+1)}_k } \frac{ \partial u^{(l+1)}_k }{ \partial u^{(l)}_j } \right) \: z^{(l-1)}_i \\
&= \left( \sum_{k=1}^{J_{l+1}} \frac{ \partial E }{ \partial u^{(l+1)}_k } w^{(l+1)}_{k, j} {f^{(l)}}' ( u^{(l)}_j ) \right) \: z^{(l-1)}_i \\
&= \left( {f^{(l)}}' ( u^{(l)}_j ) \sum_{k=1}^{J_{l+1}} \frac{ \partial E }{ \partial u^{(l+1)}_k } w^{(l+1)}_{k, j} \right) \: z^{(l-1)}_i 
\end{align}
}

となる。

なお、中間層のバイアス  b^{(l)}_j についての偏微分は、出力層のときと同様に考えて、次のようになる:

 {\displaystyle
\frac{ \partial E }{ \partial b^{(l)}_j } = {f^{(l)}}' ( u^{(l)}_j ) \sum_{k=1}^{J_{l+1}} \frac{ \partial E }{ \partial u^{(l+1)}_k } w^{(l+1)}_{k, j}
}

ところで、途中何度も出てくる  \frac{ \partial E }{ \partial u^{(l)}_j } を デルタ  \delta^{(l)}_j で表すことにする、すなわち、

 {\displaystyle
\delta^{(l)}_j = \frac{ \partial E }{ \partial u^{(l)}_j }
}

とすると、これまでの式は、次のようにまとめることが出来る:

 {\displaystyle
\begin{align}
\frac{ \partial E }{ \partial w^{(l)}_{j, i} } &= \delta^{(l)}_j z^{(l-1)}_i \\
\frac{ \partial E }{ \partial b^{(l)}_j } &= \delta^{(l)}_j \\
\delta^{(l)}_j &= \left\{ \begin{array}{ll}
\frac{ \partial E }{ \partial u^{(L)}_j } & (l = L) \\
{f^{(l)}}' ( u^{(l)}_j ) \sum_{k=1}^{J_{l+1}} \delta^{(l+1)}_k w^{(l+1)}_{k, j} & (l = 2, \cdots , L-1)
\end{array} \right.
\end{align}
}

添え字がめちゃくちゃ細くて大変だけど、地道に頑張って・・・

誤差逆伝播

まとめた式を見てみると、デルタは次の層のデルタを使って再帰的に計算できることが分かる。
そこで、出力層から入力層に向かって順番にデルタと勾配を計算していく方法を、誤差逆伝播法という。

  1. 入力  \boldsymbol{x} から、各層について  u^{(l)}_j z^{(l)}_j を計算する。
  2. 以下のようにして、デルタ  \delta^{(l)}_j を計算する:
    1. 出力層で、 \delta^{(L)}_j = \frac{ \partial E }{ \partial u^{(L)}_j } を計算する。
    2. 中間層で、 l = L-1, \cdots, 2 の順番で、デルタ  \delta^{(l)}_j を次のように計算する:
      •  \delta^{(l)}_j = {f^{(l)}}' ( u^{(l)}_j ) \sum_{k=1}^{J_{l+1}} \delta^{(l+1)}_k w^{(l+1)}_{k, j}
  3. 以下のようにして、重み  w^{(l)}_{j, i} とバイアス  b^{(l)}_j に対する偏微分を計算する:
    •  \frac{ \partial E }{ \partial w^{(l)}_{j, i} } = \delta^{(l)}_j z^{(l-1)}_i
    •  \frac{ \partial E }{ \partial b^{(l)}_j } = \delta^{(l)}_j

出力層のデルタ

出力層のデルタ  \delta^{(L)}_j は、誤差関数  E(\boldsymbol{w}) に何を使うのかで変わってくる。

誤差関数として、1つの訓練サンプル  (\boldsymbol{x}, \boldsymbol{d}) に対する二乗和誤差  \frac12 \left\| \boldsymbol{d} - \boldsymbol{y} ( \boldsymbol{x} ; \boldsymbol{w} ) \right\|^2 を使う場合、次のようになる:

 {\displaystyle
\begin{align}
\delta^{(L)}_j &= \frac{ \partial E }{ \partial u^{(L)}_j } \\
&= \frac{ \partial }{ \partial u^{(L)}_j } \left( \frac12\left\| \boldsymbol{d} - \boldsymbol{y} (\boldsymbol{x} ; \boldsymbol{w} ) \right\|^2 \right) \\
&= (d_j - y_j) \left(- {f^{(L)}}' (u^{(L)}_j) \right) \\
&= (y_j - d_j) \: {f^{(L)}}' (u^{(L)}_j)
\end{align}
}

活性化関数の導関数

デルタを計算するとき、活性化関数  f導関数  f' を使っている。

それぞれに活性化関数に対する導関数は、次のようになる:

活性化関数  f(u)  f'(u)
ロジスティック関数  \frac{1}{1 + e^{-u}}  f(u) \left( 1 - f(u) \right)
双曲線正接関数  \mathrm{tanh}(u)  1 - \mathrm{tanh}^2(u)
正規化線形関数  \mathrm{max}(u, 0)
 \left\{ \begin{array}{l} 1 \quad (u \ge 0) \\ 0 \quad (u \lt 0) \end{array} \right.
シグモイド関数
近似した関数
 \left\{ \begin{array}{l} -1 \quad (u \lt -1) \\ u \quad (-1 \le u \le 1) \\ 1 \quad (1 \lt u) \end{array} \right.
 \left\{ \begin{array}{l} 1 \quad (-1 \le u \le 1) \\ 0 \quad (\mbox{otherwise}) \end{array} \right.

バッチ学習の場合

これまでの計算は、1つの入力に対する誤差の勾配を求めるものだった。
バッチ学習やミニバッチを使う場合には、それぞれの訓練サンプルについての勾配を求めたあと、それらをすべて足し合わせると、求めたい勾配が得られる。
詳細は省略。
(行列を使うと、比較的キレイに書くことが出来る。本を参照)

今日はここまで!

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)