レポート_深層学習(前編1)

#入力層・中間層
　ニューラルネットワークの全体像
　入力層→中間層→出力層の流れである。
　例：動物に関するデータから何の動物か判断するニューラルネットワーク
　入力層：任意のデータを与える層。例：体長や耳の大きさなど
　中間層：入力層のデータにバイアスや重み付けを行う層
　出力層：中間層で計算した値が出力として出される層
　　　　　例：入力したデータからこの動物は、犬である確率0.1、猫である確率0.05、ネズミである確率0,85

確認テスト(1-2)
ディープラーニングは結局何をやろうとしているか2行以内で述べよ。また、次の中のどの値の最適化が最終目的か。
すべて選べ。
①入力値[X] ②出力値[Y] ③重み[W] ④バイアス[b] ⑤総入力[u] ⑥中間層入力[z] ⑦学習率[ρ]

最適値な出力値推定するためのパラメータである重みを最小化するパラメータを推定すること。
パラメータは重み(w)やバイアス(b)が主に推定する。

次のネットワークを紙にかけ。
入力層：2ノード1層、中間層：3ノード2層、出力層：1ノード1層

キャプチャ


確認テスト(1-4)
下記の図式に動物分類の実例を入れてみよう。

この数式をpythonで書け。

確認テスト(1-5)
1-1のファイルから 中間層の出力を定義しているソースを抜き出せ。

中間層出力の定義
z = functions.relu(u)
print_vec("中間層出力", z)

z = functions.relu(u)のuは総入力の式を表している。

演習テスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/cb3bcd0d-4400-de9c-ce12-aab206815c33.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/d5e82753-2e35-7f5d-39c5-cc05fe7e9ef3.png)
初期状態では、重み、バイアスを自身で定義し、入力値と重みを掛け、バイアスを足すことで総入力値を決定している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/9caac298-d2dc-4d02-6d63-ebee5b328151.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/4242e6a9-9f0f-ccad-edc4-5e878d0acc17.png)
次に、重みの配列をnp.zeros(2)に変更すると重み配列が[0,0]に変更され、総入力値も変化している。
その下のnp.ones(2)は重み配列が[1,1]に変更される。np.random.rand(2)は0～1の範囲内でランダムに
数字を決定する。

#活性化関数
　ニューラルネットワークにて、次の層への出力を決める非線形の関数で入力値によって次の層への
　強弱などを決定する。

中間層用と出力層用の活性化関数に分類することができる。
中間層用：ReLu関数、シグモイド関数、ステップ関数(ディープラーニングでは使用しない)
出力層用：ソフトマックス関数、恒等写像、シグモイド関数

ステップ関数
　閾値を超えると1、超えないと0を出力する関数。出力は0か1のみ
　パーセプトロンで利用されていた。課題としては、0,1間の微弱な変化に対応できず、
　線形分類可能な場合のみ(on/off)でしか利用できない。

シグモイド関数
　0,1間を微弱に変化する関数でon/off以外に信号の強弱を伝えられるようになった。
　課題として、大きな値での出力の変化が微小なため、勾配消失問題を引き起こしてしまう。
　
ReLu関数
　今最も使用されている活性化関数。勾配消失問題の解決とスパース化に貢献している。
　勾配消失問題とスパース化については後述で説明する。
　最も使用されているが用途によってはシグモイド関数が精度良い結果を生み出す場合もあるので
　エンジニアが都度最も適切な活性化関数を決定していく必要がある。

確認テスト(1-8)
配布されたソースコードから該当する箇所を抜き出せ。
z = functions.sigmoid(u)

#出力層
　誤差関数として二乗誤差を用いる。
　二乗誤差：正解データから出力データの誤差を二乗して算出。

確認テスト(1-9)
なぜ、引き算でなく二乗するのか述べよ。
引き算では±の符号の影響を受けてしまい、±によって誤差が最小になってしまうため
±符号の影響を受けないように二乗する。

1/2はどうゆう意味を持つか述べよ。
パラメータを最小化するにあたり、誤差の勾配を求めるために微分を行う。
その微分を行うときに計算を簡単にするために1/2を掛けている。

出力層用の活性化関数
　中間層との差分
　中間層は閾値の前後で信号の強弱を調整。出力層は信号の比率をそのまま変換する。

回帰タスク
　恒等写像を用いる。誤差関数は二乗誤差を用いる。

分類タスク
　二値分類：シグモイド関数を用いる。誤差関数は交差エントロピー
　多クラス分類：ソフトマックス関数を用いる。誤差関数は交差エントロピー

確認テスト(1-9)
ソフトマックス関数の①～③に該当するソースコードを示し、一行づつ処理の説明をせよ。
ソフトマックス関数のソースコード
def softmax(x):
    if x.ndim == 2:  xの次元数が2次元なら下記の処理を行う
        x = x.T　　　 xに引数xの転置を格納する
        x = x - np.max(x, axis=0)　転置した値の最大値を引き算する
        y = np.exp(x) / np.sum(np.exp(x), axis=0)　全体から選択した値の確率を求めている。
        return y.T　　　yを転置した値を返す
①に該当する場所は、def softmax(x):
②に該当する場所は、np.exp(x)
③に該当する場所は、np.sum(np.exp(x), axis=0)

確認テスト(1-10)
交差エントロピー関数の①～③に該当するソースコードを示し、一行づつ処理の説明をせよ。
交差エントロピー関数のソースコード
def cross_entropy_error(d, y):
    if y.ndim == 1:　　　 yの次元数が1次元なら下記の処理を行う
        d = d.reshape(1, d.size)　引数dを1次元の行列に変換する。
        y = y.reshape(1, y.size)  引数yを1次元の行列に変換する。
    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if d.size == y.size:          dとyのデータサイズが同じならば下記の処理を行う。
        d = d.argmax(axis=1)
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size
　　分子の数が0にならないように微小な値(1e-7)を足している。実装上の工夫
①に該当する場所は、def cross_entropy_error(d, y):
②に該当する場所は、return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) 

#勾配降下法
　勾配降下法、確率的勾配降下法、ミニバッチ勾配降下法がある。

深層学習の目的は、
最適値な出力値推定するためのパラメータである重みやバイアスを最小化するパラメータを推定すること(確認テスト1-2)。
推定する方法として、勾配降下法を用いる。


確認テスト(1-11)
該当するソースコードを探してみよう。
 network[key]  -= learning_rate * grad[key]

学習率εは学習の効率に影響を与える。
学習率が大きすぎると、最小値にたどり着かず発散してしまう。
学習率が小さすぎると、最小値にたどり着くのに時間がかなりかかってしまう。
学習回数はエポックとしてカウントする。

確率的勾配降下法(SGD)
　確率的勾配降下法は、ランダムに抽出したサンプルの誤差を用いる。
　勾配降下法は全サンプルの平均誤差を用いる。違いは覚えておくこと。
メリットは計算量の削減、局所極小解に収束するリスクの軽減、オンライン学習が可能。

確認テスト(1-11)
オンライン学習とは何か2行でまとめよ。
学習データが入力させるたびにその都度、その入力データのみを用いて学習を行うこと。

ミニバッチ勾配降下法
　ミニバッチ勾配降下法は、ランダムに分割したデータの集合に属するサンプルの平均誤差を用いる。

#誤差逆伝播法
算出した誤差を微分し、出力層から前の層に伝播する方法。これにより、不要な再帰的な計算を避ける。

確認テスト(1-14)
誤差伝播法では、不要な再帰的処理を避けることができる。既に行った計算結果を保持している
ソースコードを抽出せよ。
誤差逆伝播のソースコード

def backward(x, d, z1, y):
    print("\n##### 誤差逆伝播開始 #####")
    grad = {}
    W1, W2 = network['W1'], network['W2']
    b1, b2 = network['b1'], network['b2']
    #  出力層でのデルタ
    delta2 = functions.d_sigmoid_with_loss(d, y)
    #  b2の勾配
    grad['b2'] = np.sum(delta2, axis=0)
    #  W2の勾配
    grad['W2'] = np.dot(z1.T, delta2)
    #  中間層でのデルタ
    delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1)
    # b1の勾配
    grad['b1'] = np.sum(delta1, axis=0)
    #  W1の勾配
    grad['W1'] = np.dot(x.T, delta1)

    ①delta2 = functions.d_sigmoid_with_loss(d, y)
    交差エントロピーと、シグモイド関数の合成結果が保持されている。
　　②grad['b2'] = np.sum(delta2, axis=0)
　　①の値をベクトル変換した値が保持されている。
　　③grad['W2'] = np.dot(z1.T, delta2)

演習
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/a45d7a24-3c21-1891-deab-02eb86c40c58.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/2b0a0273-854a-2a61-89c3-bfe2456174e4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/e6254d76-dd49-3534-37b4-f844717d2761.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/5231920a-9e7d-0431-b529-69b4a79fbfb3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/0e53cbc9-14f5-5c5d-717e-b47ba75cfbf2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/88ea6c4a-784d-c9ad-1e92-9919aff5b6c0.png)
上記の結果では、ReLu関数を用いて順伝播と誤差逆伝播を行っており、結果図も綺麗に収束していることが
わかった。
次に順伝播と誤差逆伝播の関数をシグモイド関数に変更した場合の結果が下記の結果図である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/2dbf4221-1fff-f09b-2abd-5075939eaf34.png)
シグモイド関数に変更することで収束にばらつきが発生していることが可視化でわかる。
コードの実装上、順伝播の活性化関数と誤差逆伝播の誤差関数はセットで変更しなければならない。

また訓練データのx値の範囲を変更した場合の結果がが下記の結果図である。x値の範囲を変化させても収束にばらつきが発生することが確認できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548419/1d3a84b6-1d5e-175a-2416-e1fe454c13f2.png)

確認テスト(1-15)
2つの空欄に該当するソースコードを探せ。
上の空欄
delta2 = functions.d_mean_squared_error(d, y)
下の空欄
grad['W2'] = np.dot(z1.T, delta2)