LoginSignup
0
0

More than 3 years have passed since last update.

深層学習 Day 3 - Section 1 再帰型ニューラルネットワークの概念 のまとめ

Last updated at Posted at 2020-11-20

この記事は個人的なお勉強用のメモです。

このお勉強の位置

深層学習 Day 3

Section 1 再帰型ニューラルネットワークの概念 ← これ
Section 2 LSTM
Section 3 GRU
Section 4 双方向RNN
Section 5 Seq2Seq
Section 6 Word2vec
Section 7 Attention Mechanism

講義

RNN

再帰型ニューラルネットワーク(Recurrent Neural Network)
時系列データに対応可能なNN

後で登場するLSTMとかを含めてRNNと呼ぶ場合、
今回のRNNをシンプルなRNNと呼ぶことも。

時系列データ

時間的順序を追って一定間隔ごとに観察され、
相互に統計的依存関係が認められるようなデータの系列

  • 音声データ
  • テキストデータ
  • 株価推移のデータ(タイムスタンプがあるデータ)
  • 月ごとの訪問数

構成

  1. 入力データ $x$ に重みを掛けて $s$ が出力される。
    $s$ は次の概念 $s_0$ に用いられる。
  2. 以下の2つを加算して $s_1$ を計算する。
    ・$s_0$ に重みを掛けた値
    ・次の入力値 $x_1$
  3. $s_1$ に活性化関数を実行して重みを掛けて、$y_1$ として出力する。
  4. 1から3まで繰り返し

※講義の図では $y$ から $s$ に矢印が伸びているが、矢印の向きが逆だと思う。

重みは3種類
$W_{(in)}$:$x$ に掛けて $s$ を出力する。
$W$:$s_{i-1}$ に掛けて $s_i$ を出力する。
$W_{(out)}$:$s$ に掛けて $y$ を出力する。

構成図(一部)

image.png

数式

\begin{align}
u^t&=W_{(in)}x^t+Wz^{t-1}+b\\
z^t
&=f(u^t)\\
v^t&=W_{(out)}z^t+c\\
y^t
&=g(v^t)\end{align}

$b$:バイアス
$c$:バイアス

u[:, t+1] = np.dot(X, W_in) + np.dot(z[:, t].reshape(1, -1), W)
z[:, t+1] = functions.sigmoid(u[:, t+1])
y[:, t] = functions.sigmoid(np.dot(z[:, t+1].reshape(1, -1), W_out))

特徴

時系列モデルを扱うには、初期の状態と過去の状態 t-1 の状態を保持し、
次の時間での t を再帰的に求める再帰構造が必要。

RNNについて

BPTT

BPTTとは

Back Propagation Through Time
誤差逆伝播法の一種。

BPTTの数学的記述

3つの重み

\begin{align}
\frac{\partial E}{\partial W_{(in)}}
&=\frac{\partial E}{\partial u^t}\Biggl[\frac{\partial u^t}{\partial W_{(in)}}\Biggr]^T\\
&=\delta^t \bigl[x^t\big]^T
\end{align}
\begin{align}
\frac{\partial E}{\partial W_{(out)}}
&=\frac{\partial E}{\partial v^t}\Biggl[\frac{\partial v^t}{\partial W_{(out)}}\Biggr]^T\\
&=\delta^{out,t} \bigl[z^t\big]^T
\end{align}
\begin{align}
\frac{\partial E}{\partial W}
&=\frac{\partial E}{\partial u^t}\Biggl[\frac{\partial u^t}{\partial W}\Biggr]^T\\
&=\delta^t \bigl[z^{t-1}\big]^T
\end{align}

2つのバイアス

\begin{align}
\frac{\partial E}{\partial b}
&=\frac{\partial E}{\partial u^t}\frac{\partial u^t}{\partial b}\\
&=\delta^t
\end{align}
\begin{align}
\frac{\partial E}{\partial c}
&=\frac{\partial E}{\partial v^t}\frac{\partial v^t}{\partial c}\\
&=\delta^{out,t}
\end{align}

重みのサンプルコード

np.dot(X.T, delta[:,t].reshape(1,-1))
np.dot(z[:,t+1].reshape(-1,1), delta_out[:,t].reshape(-1,1))
np.dot(z[:,t].reshape(-1,1), delta[:,t].reshape(1,-1))
\begin{align}
\frac{\partial E}{\partial u^t}
&=
\frac{\partial E}{\partial v^t}
\frac{\partial v^t}{\partial u^t}
\\
&=
\frac{\partial E}{\partial v^t}
\frac{\partial \Bigl(W_{(out)}f(u^t)+c\Bigr)}{\partial u^t}
\\
&=f'(u^t)W_{(out)}^T \delta^{out,t}
\\
&=
\delta^t
\\
\delta ^{t-1}
&=
\frac{\partial E}{\partial u^{t-1}}
\\
&=
\frac{\partial E}{\partial u^{t}}
\frac{\partial u^t}{\partial u^{t-1}}
\\
&=
\delta^t\Biggl(
\frac{\partial u^t}{\partial z^{t-1}}
\frac{\partial z^{t-1}}{\partial u^{t-1}}
\Biggr)
\\
&=
\delta^t
W\biggl(f'(u^{t-1})\biggr)
\\
\delta^{t-z-1}&=\delta^{t-z}\Bigl(Wf'(u^{t-z-1})\Bigr)
\end{align}
delta[:,t] = (np.dot(delta[:,t+1].T, W.T) + np.dot(delta_out[:,t].T, W_out.T)) *
  functions.d_sigmoid(u[:,t+1])

パラメータの更新式

W_{(in)}^{t+1}=W_{(in)}^t-\epsilon \frac{\partial E}{\partial W_{(in)}}
=W_{(in)}^t -\epsilon \sum_{z=0}^{T_t} \delta^{t-z}\Bigl[x^{t-z}\Bigr]^T\\
W_{(out)}^{t+1}=W_{(out)}^{t}-\epsilon \frac{\partial E}{\partial W_{(out)}}
=W_{(in)}^t - \epsilon \delta^{out,t}\Bigl[z^{t}\Bigr]^T\\
W^{t+1}=W^{t}-\epsilon \frac{\partial E}{\partial W}
=W^t - \epsilon \sum_{z=0}^{T_t} \delta^{t-z}\Bigl[x^{t-z-1}\Bigr]^T\\
b^{t+1}=b^t-\epsilon  \frac{\partial E}{\partial b}=b^t-\epsilon \sum_{z=0}^{T_t} \delta^{t-z}\\
c^{t+1}=c^t-\epsilon  \frac{\partial E}{\partial c}=c^t-\epsilon \delta^{out,t}\\

講義では $W^{t+1}$ の更新式に $W_{(in)}^t$ が書かれているが、
$W^t$ の間違いだと思う。

W_in -= learning_rate * W_in_grad
W_out -= learning_rate * W_out_grad
W -= learning_rate * W_grad

コード演習問題

for t in reversed(range(n_seq)):
  dv += np.dot(do[:, t].T, hiddens[:, t]) / batch_size
  delta_t = do[:, t].dot(V)
  for bptt_step in reversed(range(t+1)):
    dW += np.dot(delta_t.T, xs[:, bptt_step]) / batch_size
    dU += np.dot(delta_t.T, hiddens[:, bptt_step-1]) / batch_size
    delta_t = delta_t.dot(U)
  return dW, dU, dV

$\frac{\partial h_t}{\partial h_{t-1}}=U$ であるため、
過去に遡るたびに $U$ が掛けられる。
後で復習。

実装演習

2つの数値の足し算を学習するプログラム
2つの数値と正解値をそれぞれ2進数のビット列で表現する。
2つの数値のビット列の下位ビットをペアにして、順番に入力データとして与える。
このとき、前のビット計算の途中の値を保存し、次のビット計算で参照する(この部分がRNN)。

そのまま実行

weight_init_std = 1
learning_rate = 0.1
hidden_layer_size = 16

image.png

横軸:学習回数
縦軸:誤差

学習回数が増えるにつれて、誤差が小さくなっている。
これはRNNが足し算を学習したということか。

weight_init_std=10

image.png

weight_init_std=1のときに比べて、誤差のばらつきが大きい。
また、収束したとは言えない。

weight_init_std=0.1

image.png

学習が進んでいない。
重みが小さいため、最適値まで到達していないということか。

learning_rate=1

image.png

収束が速くなった。
加えて誤差も見た目ではゼロになっている。

誤差がゼロというのは過学習の可能性を疑うが
この場合は毎回新規にデータを生成して誤差を測定しているため
過学習にはあたらないはず。

hidden_layer_size=160

image.png

中間層のノードの数を10倍の160個にしたら、
誤差のばらつきが非常に大きくなった。
これは未知のデータに対する過学習の可能性がある。
(やっていることは毎回未知のデータに対する測定なので。)

Xavierの初期値

実装メモ
Xavierの初期値やHeの初期値の場合は、weight_init_stdを掛ける必要はない。

image.png

Xavierの初期値を指定すると、学習が悪化した。

Heの初期値

image.png

Xavierの初期値の場合よりはまともだが、何もしない方が学習の進み具合が良い。

中間層の活性化関数 ReLU

image.png

変更したソースは模範解答と全く同じだが、
なぜか全く学習が進まない。

中間層の活性化関数 tanh

自分の解答

def d_tanh(x):
    return 4 / (np.exp(x) + np.exp(-x)) ** 2

模範解答

def d_tann(x):
    return 1/(np.cosh(x) ** 2)

式は違うが同じ意味。

image.png

学習回数が2000回を超えるくらいから急激に誤差が少なくなった。
不思議に思って何回か実行してみたが、傾向は同じ。
4000回に到達するころには誤差はゼロに近い。

確認テスト

重みの説明

3つ目の重みは、中間層から次の中間層を定義する際にかけられる重み。

連鎖率の復習

$z=t^2$ ⇒ $\frac{dz}{dt}=2t$
$t = x+y$ ⇒ $\frac{dt}{dx}=1$

\begin{align}
\frac{dz}{dx}
&=\frac{dz}{dt}\frac{dt}{dx}\\
&=2t\times 1\\
&=2(x+y)
\end{align}

y1を数式で表す

使用する変数:$x, s_0, s_1, W_{(in)}, W, W_{(out)}$
中間層の出力にシグモイド関数 $g(x)$ を作用させる。

\begin{align}
s_1
&=g(W_{(in)}x_1+Ws_0+b)\\
y_1
&=W_{(out)}s_1+c\\
\end{align}
  • $s_0$ や $s_1$ というのが、活性化関数を作用させる前の値なのか後なのかわからなかった。
    活性化関数を作用させた後という前提で解答を書いた。
  • 問題文に $g(x)$ と書いてあるのでそのまま $g(x)$ と書いた。
  • 出力層には活性化関数を書かなかった。

模範解答はこちら。

\begin{align}
z_1&=sigmoid(s_0W+x_1W_{(in)}+b)\\
y_1&=sigmoid(z_1W_{(out)}+c)
\end{align}

模範解答は $s$ と $z$ を厳密に使い分けているのだろうか。
($s_0W$ とあることから、$s_0$ は前の中間層で活性化関数を作用させた後である。
一方で、$z_1=sigmoid(...)$ とあることから、$z_1$ も中間層で活性化関数を
作用させた後である。しかし、上記の2つの変数名が $s$ と $z$ とで一致しない。)

修了テスト~練習問題~

BPTTに関する問題はない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0