UnityとゲームAIと将棋

Unity、Pythonを中心にゲーム開発やゲームAI開発の技術メモ等、たまに将棋も

【機械学習】FNNの内部計算メモ

本記事の概要

大学・大学院時代に研究を始める際、ニューラルネットの基礎を学ぶためC++でFNNとRNNのスクラッチ実装に取り組んだことがあったのですが、その際にニューラルネットの内部計算がどのようになっているのかを理解するため、計算グラフをもとに内部計算を順に書き出して手計算したという経験があります。その時のノートを備忘録的にメモしておこうと思います。

FNNの計算グラフ

FNNの計算グラフ

※各パラメタ・要素の説明
 x : 入力値
 W_{ih} : 入力層と中間層の結合重み
 b_h : 中間層におけるバイアス
 h : 中間層への入力。内部状態とも言うらしい。
 tanh : 活性化関数
 d : 中間層の出力。コンテキストとも言うらしい。
 W_{do} : 中間層と出力層の結合重み
 b_o : 出力層におけるバイアス
 y : 出力層における出力値

今回は上のような3層FNNを考えてみます。厳密には結合重みは行列でバイアスはベクトルなので、太字にするなりして表記を区別しないといけないのですが、このメモでは簡便化のため区別しないで書きます。

FNNの内部計算

ニューラルネットの学習は基本的に順方向計算、誤差逆伝播、パラメタ更新の3つを繰り返して、パラメタ値(結合重みとバイアス)を誤差関数が最小化される、すなわちニューラルネットの出力と目標値が一致するように更新していくことを目的としている

誤差関数

誤差関数の種類は沢山あるが今回は平均二乗誤差(出力と教師データ \hat{y} の差を二乗して2で割ったもの)を用いる。


E=\dfrac{1}{2}\left(y-\hat{y}\right)^2

※なぜ2で割るのか?→微分した時に係数が1になるように調整するため。

順方向計算


h=W_{ih}x+b_h \\
d=tanh(h) \\
y=tanh(W_{do}d+b_o)

今回は活性化関数として tanh を用いる。活性化関数は何を目的とした学習なのか(クラス分類、予測等)や出力の値域がどういった範囲になるかということに応じて適切なものを選択する。

誤差逆伝播


\dfrac{\partial E}{\partial W_{do}}=\dfrac{\partial E}{\partial y}\cdot\dfrac{\partial y}{\partial W_{do}}=(y-\hat{y})(1-y^2)d \\
\dfrac{\partial E}{\partial b_o}=\dfrac{\partial E}{\partial y}\cdot\dfrac{\partial y}{\partial b_o}=(y-\hat{y})(1-y^2) \\
\dfrac{\partial E}{\partial W_{ih}}=\dfrac{\partial E}{\partial y}\cdot\dfrac{\partial y}{\partial d}\cdot\dfrac{\partial d}{\partial h}\cdot\dfrac{\partial h}{\partial W_{ih}}=(y-\hat{y})(1-y^2)W_{do}(1-d^2)x \\
\dfrac{\partial E}{\partial b_h}=\dfrac{\partial E}{\partial y}\cdot\dfrac{\partial y}{\partial d}\cdot\dfrac{\partial d}{\partial h}\cdot\dfrac{\partial h}{\partial b_h}=(y-\hat{y})(1-y^2)W_{do}(1-d^2)

パラメタ更新式


W_{do}\leftarrow W_{do}-\alpha\cdot\dfrac{\partial E}{\partial W_{do}} \\
b_o\leftarrow b_o-\alpha\cdot\dfrac{\partial E}{\partial b_o} \\
W_{ih}\leftarrow W_{ih}-\alpha\cdot\dfrac{\partial E}{\partial W_{ih}} \\
b_h\leftarrow b_h-\alpha\cdot\dfrac{\partial E}{\partial b_h}

 \alpha は学習率で、逆伝播された誤差を用いてパラメタをどれだけ更新するかを決める値。大きいほど誤差に大きく影響を受ける。