深層学習（後編・day 3）レポート

# 目次
- 深層学習（後編・day 3）
  - Section1　再帰型ニューラルネットワークの概念
  - Section2　LSTM
  - Section3　GRU
  - Section4　双方向RNN
  - Section5　Seq2Seq
  - Section6　Word2Vec
  - Section7　Attention Mechanisim

# Section1　再帰型ニューラルネットワークの概念

### RNNとは？
時系列データに対応可能なニューラルネットワーク
### 時系列データとは？
時間的順序を追って一定間隔ごとに観察され、しかも相互に統計的依存関係が認められるようなデータの系列
### 具体的な時系列データとは？
 - 音声データ
 - テキストデータ

### BPTT(Backpropagation Through Time)とは？
RNNにおいてのパラメータ調整方法の一種

 - 誤差逆伝播法の一種

#### 誤差逆伝播法とは？
   - 計算結果(=誤差)から微分を逆算することで、不要な再帰的計算を避けて微分できる

###【考察】
###【実装演習結果】

```python:
import numpy as np
from common import functions
import matplotlib.pyplot as plt

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

# データを用意
# 2進数の桁数
binary_dim = 8
# 最大値 + 1
largest_number = pow(2, binary_dim)
# largest_numberまで2進数を用意
binary = np.unpackbits(np.array([range(largest_number)],dtype=np.uint8).T,axis=1)
input_layer_size = 2
hidden_layer_size = 100
output_layer_size = 1
weight_init_std = 1
learning_rate = 0.01
iters_num = 10000
plot_interval = 100
# ウェイト初期化 (バイアスは簡単のため省略)
W_in = weight_init_std * np.random.randn(input_layer_size, hidden_layer_size)
W_out = weight_init_std * np.random.randn(hidden_layer_size, output_layer_size)
W = weight_init_std * np.random.randn(hidden_layer_size, hidden_layer_size)
# Xavier
W_in = np.random.randn(input_layer_size, hidden_layer_size) / (np.sqrt(input_layer_size))
W_out = np.random.randn(hidden_layer_size, output_layer_size) / (np.sqrt(hidden_layer_size))
W = np.random.randn(hidden_layer_size, hidden_layer_size) / (np.sqrt(hidden_layer_size))
# He
W_in = np.random.randn(input_layer_size, hidden_layer_size) / (np.sqrt(input_layer_size)) * np.sqrt(2)
W_out = np.random.randn(hidden_layer_size, output_layer_size) / (np.sqrt(hidden_layer_size)) * np.sqrt(2)
W = np.random.randn(hidden_layer_size, hidden_layer_size) / (np.sqrt(hidden_layer_size)) * np.sqrt(2)
# 勾配
W_in_grad = np.zeros_like(W_in)
W_out_grad = np.zeros_like(W_out)
W_grad = np.zeros_like(W)
u = np.zeros((hidden_layer_size, binary_dim + 1))
z = np.zeros((hidden_layer_size, binary_dim + 1))
y = np.zeros((output_layer_size, binary_dim))
delta_out = np.zeros((output_layer_size, binary_dim))
delta = np.zeros((hidden_layer_size, binary_dim + 1))
all_losses = []
for i in range(iters_num):
    # A, B初期化 (a + b = d)
    a_int = np.random.randint(largest_number/2)
    a_bin = binary[a_int] # binary encoding
    b_int = np.random.randint(largest_number/2)
    b_bin = binary[b_int] # binary encoding
    # 正解データ
    d_int = a_int + b_int
    d_bin = binary[d_int]
    # 出力バイナリ
    out_bin = np.zeros_like(d_bin)
    # 時系列全体の誤差
    all_loss = 0    
    # 時系列ループ
    for t in range(binary_dim):
        # 入力値
        X = np.array([a_bin[ - t - 1], b_bin[ - t - 1]]).reshape(1, -1)
        # 時刻tにおける正解データ
        dd = np.array([d_bin[binary_dim - t - 1]])
        u[:,t+1] = np.dot(X, W_in) + np.dot(z[:,t].reshape(1, -1), W)
        z[:,t+1] = functions.sigmoid(u[:,t+1])
        z[:,t+1] = functions.relu(u[:,t+1])
        z[:,t+1] = np.tanh(u[:,t+1])    
        y[:,t] = functions.sigmoid(np.dot(z[:,t+1].reshape(1, -1), W_out))
        #誤差
        loss = functions.mean_squared_error(dd, y[:,t])
        delta_out[:,t] = functions.d_mean_squared_error(dd, y[:,t]) * functions.d_sigmoid(y[:,t])        
        all_loss += loss
        out_bin[binary_dim - t - 1] = np.round(y[:,t])

    for t in range(binary_dim)[::-1]:
        X = np.array([a_bin[-t-1],b_bin[-t-1]]).reshape(1, -1)        
        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])
        delta[:,t] = (np.dot(delta[:,t+1].T, W.T) + np.dot(delta_out[:,t].T, W_out.T)) * functions.d_relu(u[:,t+1])
        delta[:,t] = (np.dot(delta[:,t+1].T, W.T) + np.dot(delta_out[:,t].T, W_out.T)) * d_tanh(u[:,t+1])    
        # 勾配更新
        W_out_grad += np.dot(z[:,t+1].reshape(-1,1), delta_out[:,t].reshape(-1,1))
        W_grad += np.dot(z[:,t].reshape(-1,1), delta[:,t].reshape(1,-1))
        W_in_grad += np.dot(X.T, delta[:,t].reshape(1,-1))
    
    # 勾配適用
    W_in -= learning_rate * W_in_grad
    W_out -= learning_rate * W_out_grad
    W -= learning_rate * W_grad
    W_in_grad *= 0
    W_out_grad *= 0
    W_grad *= 0
    if(i % plot_interval == 0):
        all_losses.append(all_loss)        
        print("iters:" + str(i))
        print("Loss:" + str(all_loss))
        print("Pred:" + str(out_bin))
        print("True:" + str(d_bin))
        out_int = 0
        for index,x in enumerate(reversed(out_bin)):
            out_int += x * pow(2, index)
        print(str(a_int) + " + " + str(b_int) + " = " + str(out_int))
        print("------------")

lists = range(0, iters_num, plot_interval)
plt.plot(lists, all_losses, label="loss")
plt.show()
```
![simple RNN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/a431d3a1-4b03-3324-9b8e-e278f7ae3ae0.png)

###【確認テスト】
Q.サイズ5x5の入力画像を、サイズ3x3のフィルタで畳み込んだ時の出力画像のサイズを答えよ。なおストライドは2、パディングは1とする。
A.出力画像のサイズは 3x3

Q.RNNのネットワークには大きく分けて3つの重みがある。1つは入力から現在の中間層を定義する際にかけられる重み、1つは中間層から出力を定義する際にかけられる重みである。残りの1つの重みについて説明せよ。
A.一つ前の中間層の出力を、次の中間層の入力にする際にかけられる重み

Q.連鎖律の原理を使い、dz/dxを求めよ。
![math-20200513_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/83485b67-5efa-993d-1d17-316f8eee778f.png)
A.
![math-20200513_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/1913ada9-3c82-d6d6-9ec3-c5852687888b.png)

Q.下図のy1をx・s0・s1・Win・W・Woutを用いて数式で表せ。
※バイアスは任意の文字で定義せよ。
※また中間層の出力にシグモイド関数g(x)を作用させよ。
![BITT.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/bc780506-5b90-bc34-6279-a59ed2289abc.png)
A.
![math-20200525.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/036c025c-f399-9e00-9e38-4af34130c583.png)

###【演習問題】

# Section2　LSTM

### 勾配爆発とは？
勾配が層を逆伝播するごとに指数関数的に大きくなっていきます

### CEC
勾配消失および勾配爆発の解決方法として、勾配が、1であれば解決できる。

入力・出力ゲートの役割とは？

 - 入力・出力ゲートを追加することで、それぞれのゲートへの入力値も重みを、重み行列W, Uで可変可能とする。
   - CECの課題を解決、

###【考察】
###【実装演習結果】
###【確認テスト】
Q.シグモイド関数を微分した時に、入力値が0の時に最大値をとる。その値として正しいものを選択肢から選べ。
(1) 0.15 (2) 0.25 (3) 0.35 (4) 0.45 
A.(2) 

Q.以下の文章をLSTMに入力し空欄に当てはまる単語を予測したいとする。文中の「とても」という言葉は空欄の予測においてなくなっても影響を及ぼさないと考えられる。
このような場合、どのゲートが作用すると考えられる。
「映画おもしろかったね。ところで、とてもお腹が空いたから何か＿＿＿。」

A.忘却ゲート

###【演習問題】

![gradient_clipping.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/a1c9dd95-09dd-b4ad-1bda-8e2fcbd24431.png)
A.(1)

![lstm.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/ed26cdd3-e44d-ae00-17ae-0fc469d112b6.png)
A.(3)

# Section3　GRU

### GRUとは？
従来のLSTMでは、パラメータが多数存在していたため、計算負荷が大きかった。しかし、GRUでは、そのパラメータを大幅に削減し、精度は同等またはそれ以上が望める様になった構造。

###【考察】
###【実装演習結果】



###【確認テスト】

Q.LSTMとCECが抱える課題について、それぞれ簡潔に述べよ。
A.
LSTM：パラメータ数が多くて、計算負荷が大分かかる
CEC：最適なパラメータである重み1で画一なので学習が行えない

Q.LSTMとGRUの違いを簡潔に述べよ。
A.
LSTM：パラメータ数が多い
GRU：パラメータ数が少ない

###【演習問題】
![gru.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/ee03fbc5-4952-5a10-0515-faa609c8442a.png)
A.(4)

# Section4　双方向RNN

### 双方向RNNとは？
過去の情報だけでなく、未来の情報を加味することで、精度を向上させるためのモデル

e.g. 文章の推敲、機械翻訳等

###【考察】
###【実装演習結果】
###【確認テスト】

![bidirectional_rnn_net.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/8a8f63b7-36d7-0ba6-277c-95bb7ee7e9c6.png)
A.(4)

###【演習問題】

# Section5　Seq2Seq

### Seq2Seqとは？
Encoder-Decoderモデルの一種

### Seq2Seqの具体的な用途とは？
機械対話や、機械翻訳などに使用

### EncoderRNN
- Taking: 文章を単語等のトークン毎に分割し、トークンごとにUDに分割する。
- Embedding: IDから、そのトークンを表す分散表現ベクトルに変換。
- Encoder RNN: ベクトルを順番にRNNに入力していく。

### オートエンコーダーとは？
 - 教師なし学習の一つ
    - 学習時の入力データは訓練データのみで教師データは利用しない。
  e.x.) MNISTの場合、28x28の数字の画像を入れて同じ画像を出力するニューラルネットワーク

###【考察】
###【実装演習結果】
###【確認テスト】

Q.下記の選択肢から、Seq2Seqについて説明しているものを選べ。
(1)時刻に関して順方向と逆方向のRNNを構成し、それらの2つ中間層表現を特徴量としてして利用するものである。
(2)RNNを用いたEncorder-Decoderモデルの一種であり、機械翻訳などのモデルに使われる。
(3)構文木などの木構造に対して、隣接単語から表現ベクトル（フレーズ）を作るという演算を再帰的に行い（重みは共通）、文全体の表現ベクトルを得るニューラルネットワークである。
(4)RNNの一種であり、単純なRNNにおいて問題となる勾配消失問題をCECとゲートの概念を導入することで解決したものである。
A.(2)

![encode.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60541/62e3ecc7-5deb-9417-4093-739758b02f7c.png)
A.(1)

Q.Seq2SeqとHRED、HREDとVHREDの違いを述べよ。
A.
Seq2SeqとHRED：Seq2Seqは一問しかできない、n-1個の発話の文脈に即して回答できる。
HREDとVHRED：HREDは同じ会話の文脈で同じ回答が返ってくる、VHREDは同じ会話の文脈でランダムで内容に違うものが返ってくる。

Q.VAEに関する下記の説明文中の空欄に当てはまる言葉を答えよ。
A.自己符号化の潜在変数に確率分布を導入したもの。

###【演習問題】

# Section6　Word2Vec

### Word2Vecとは？
固定長形式で単語を表したもの

###【考察】
###【実装演習結果】
###【確認テスト】
###【演習問題】

# Section7　Attention Mechanisim

### Attentionとは？
入力と出力のどの単語が関連しているのかの関連度を学習する仕組み

###【考察】
###【実装演習結果】
###【確認テスト】
Q.RNNとWord2Vec、Seq2SeqとAttentionの違いを完結に述べよ。
A.
RNNとWord2Vec：Word2Vecは重みの生成ロジック：ボキャブラリ×任意の単語ベクトル、重みに対しての計算が現実的、RNNはボキャブラリ×ボキャブラリ
Seq2SeqとAttention：Seq2Seqは固定長・固定超次元できしかできない、Attentionは重要度の概念を用いて長い文章での翻訳が成り立つ

###【演習問題】