ラビットチャレンジ　-深層学習day1,day2-

# はじめに

本記事は、E資格受験を得るためのレポート記事になります。
プログラム名は、ラビットチャレンジ。そして今回は、深層学習編(day1,day2)です。

# 入力層 ~　中間層
ニューラルネットワークの全体像として、大きく分けて入力層、中間層、出力層がある。
入力画像、特徴量など、数値変換したものを入力層に入れることで、中間層へ経て出力層で算出される。

基本となる式を下記に記載する。

```math
　y = W*x + b
```
W:重み　x:入力値　b:バイアス

・確認テスト1
ディープラーニングは、結局何をやろうとしているか2行以内で述べよ。また、次の中のどの値の最適化が最終目的か。全て選べ。

①入力値[ X] ②出力値[ Y]③重み[W]④バイアス[b]⑤総入力[u] ⑥中間層入力[ z]⑦学習率[ρ]NN全体像確認テスト

[回答]　
③重み[W]④バイアス[b]

中間層を用いてニューラルネットワークから、入力から出力までを行うモデルの構築を
行うこと。

・確認テスト2

```math
　w = [w_{1},w_{2}....w_{l}]
```
```math
  x = [x_{1},x_{2}....x_{l}]
```
のとき、下記の式をpythonで書け。

```math
  u  = w_{1}x_{1}+w_{2}x_{2}+w_{3}x_{3}+w_{4}x_{4}+b
```
[回答]
u1 =np.dot(x1,w1) + b

・確認テスト3
![ニューラルネットワーク.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/672a9636-e7c0-42d4-1ef0-b71d3544c50c.png)

[回答]
動物の特徴量（身長、体重etc）などを入力層（x1,x2...）を入れる。出力層では、動物のあてはまる確率(0~1)がでてくる。

・確認テスト4
次のネットワークを紙にかけ

入力層：２ノード１層
中間層：３ノード２層
出力層：１ノード１層

[回答]
![ニューラルネットワークモデル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/580377fb-33b2-f3ec-afae-586fb7a47e47.png)

各々の層をノードと層で表記しているのが確認できる。

・実装事例

順伝播（単層・複数ユニット）google olaboratory上で実行してみる。

```python

# 重み
W = np.array([
    [0.1, 0.2, 0.3], 
    [0.2, 0.3, 0.4], 
    [0.3, 0.4, 0.5],
    [0.4, 0.5, 0.6]
])


print_vec("重み", W)

# バイアス
b = np.array([0.1, 0.2, 0.3])
print_vec("バイアス", b)

# 入力値
x = np.array([1.0, 5.0, 2.0, -1.0])
print_vec("入力", x)


#  総入力
u = np.dot(x, W) + b
print_vec("総入力", u)

# 中間層出力
z = functions.sigmoid(u)
print_vec("中間層出力", z)
```

出力結果は以下の通り。

```python
*** 重み ***
[[0.1 0.2 0.3]
 [0.2 0.3 0.4]
 [0.3 0.4 0.5]
 [0.4 0.5 0.6]]

*** バイアス ***
[0.1 0.2 0.3]

*** 入力 ***
[ 1.  5.  2. -1.]

*** 総入力 ***
[1.4 2.2 3. ]

*** 中間層出力 ***
[0.80218389 0.90024951 0.95257413]
```


# 活性化関数
別名伝達関数。ニューラルネットワークにおいて、入力された数値（入力値）から出力値を決定する関数。非線形が多い。機械学習における人工ニューラルネットワークは人間における生体ニューラルネットワークの基本的な挙動を模倣している。
例として、ステップ関数、シグモイド関数、ReLU関数などがあげられる。

・ステップ関数
出力関数は0か1ででてくる。閾値で区切られている。

実装事例

```python
import matplotlib.pyplot as plt
import numpy as np

def step_function(x):
  if x > 0:
    return 1
  else:return 0

x = np.linspace(-10, 10, 100)
y = [step_function(i) for i in x]
plt.plot(x, y)
plt.show()
```
![ステップ関数.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/ca800e25-d916-cc94-0ba3-f93745dd78b4.png)


・シグモイド関数
出力値として0　~ 1をゆるやかに変化できるのが特徴。

実装事例

```python
import matplotlib.pyplot as plt
import numpy as np

def sigmoid(x):
   return 1/(1 + np.exp(-x))

x = np.linspace(-10, 10, 100)
y = [sigmoid(i) for i in x]
plt.plot(x, y)
plt.show()
```
![シグモイド.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/ac785e62-7537-f083-6257-319d3c930375.png)



・ReLU関数
現在、もっとも使われている活性化関数。
勾配消失問題の回避とスパース化に貢献。

実装事例

```python
import matplotlib.pyplot as plt
import numpy as np

def relu(x):
  return np.maximum(0, x)

x = np.linspace(-10, 10, 100)
y = [relu(i) for i in x]
plt.plot(x, y)
plt.show()
```

![relu.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/f6ef74b8-f7b5-d26d-6f8c-a0dc63b18cdc.png)

・確認テスト1
線形と非線形の違いを図に書いて簡易に説明せよ

例として

![線形と非線形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/1e398b36-812c-bf52-2f4b-f987f3fcab9f.png)


線形は比例（直線）で表記できるのに対し、非線形は比例関係ではない直線以外（曲線）などを指す。線形は加次性、斉次性を満たすが、非線形は満たさない。

・確認テスト2
![確認テスト.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/964079c3-dc2a-d6b5-3cfd-9a5e51a51a0c.png)

[回答]

```python
Z1=functions.sigmoid(u)
```


# 出力層

出力層には、入力値をもとに得られた値（予測値）を出力する機能のほかに、正解値との誤差を算出する機能を持つ。この予測値と正解値の誤差を損失とよび、この損失を最小/最大にすることで、機械学習モデルを最適化する。
誤差関数は以下の数式で表現される。


```math
 E_{n}(w) = \frac{1}{2}\sum_{j_{i}}^{j}(y_{i}-d_{i})^2
```

y:正解値、d:出力値
今回は２乗和誤差を使用している。

コードでの表記は下記の通り。

```python
loss = functions.mean_squared_error(d, y)
```


・確認テスト1
![確認テスト.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/9e7fb888-eafc-fcf7-90e7-092bdc25e6d9.png)

[回答]
・負の値がでる場合があり、２乗をいれて正の値へと揃えるため。
・誤差逆電幡式で誤差関数の微分を用いるためその計算を楽に扱えるようにするため。




# 勾配降下法

ニューラルネットワークを学習させる手法。
誤差E(w)を最小化するパラメーターｗを発見すること
→勾配降下法を用いて、パラメータｗの最適化を行う。

数式は下記の通り

```math
 W^{t+1} =W^t-ε▽E\\
▽E =\frac{\delta E}{\delta w}

```

```math
▽E =\frac{\delta E}{\delta W_{1}}=[\frac{\delta E}{\delta W_{1}}....\frac{\delta E}{\delta W_{m}}]
```
εは学習率を示す。学習率によって学習の効率が大きく異なる。

学習率が小さすぎる場合は、発散することはないが、収束するまでに時間がかかるので注意。
また、学習率が大きすぎる場合は最小値にいつまでも届くかず、発散してしまう。

イメージは、間違えた箇所（ε▽E）を次に生かすようなイメージ。

・確認テスト1
![確認テスト確率勾配.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/e515311b-6001-4fb6-7268-714db8faf1dc.png)

[回答]

```python
network[key]  -= learning_rate* grad[key]
grad = backward(x, d, z1, y)
```

確率勾配的降下法（SGD）
→基本的な数式は勾配降下法と同じ。
違いとしては、勾配降下法が全サンプルの平均誤差を対象しているのに対し確率的勾配降下法はランダムに抽出したサンプルの誤差を対象にしている点である。

確率的勾配降下法のメリットとしては、
・データが冗長な場合の計算コストの軽減
・望まない局所極小解に収縮するリスクの軽減
・オンライン学習ができる


・確認テスト2
オンライン学習とは何か。２行でまとめよ。
学習データが入ってきたらその度にパラメーターを更新し学習を進めていく手法。
それに対しバッチ学習は一度にすべての学習データを元にパラメーターの更新を行う。

・確認テスト3

```math
W^{t+1} =W^(t) - εE_{t}
```
を図に書いて説明せよ。
![更新.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/5cfcf067-f71e-4e66-9f54-601c22ea4d3f.png)

生じた誤差（ε▽Et）を新たな入力値で更新しているのを確認できる。

・実装演習
確率勾配降下法について、以下に記載する。

```python

# 勾配降下の繰り返し
for dataset in random_datasets:
    x, d = dataset['x'], dataset['d']
    z1, y = forward(network, x)
    grad = backward(x, d, z1, y)
    # パラメータに勾配適用
    for key in ('W1', 'W2', 'b1', 'b2'):
        network[key]  -= learning_rate * grad[key]
```
![確率.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/5e61c1f7-4512-af85-2e93-7be7dc37764f.png)



# 誤差逆伝番法
別名バックプロパゲーション。算出された誤差を出力層側から順に微分し前層の層へと伝搬。数値微分とは異なり、最小限の計算で各パラメータでの微分値を解析的に算出する方法。詳細の図を下記に記載する。学習には、オンライン学習とバッチ学習が存在する。

![誤差逆伝搬法.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/af8c5959-fe2d-9d87-fa09-2cf380d14c3a.png)


・確認テスト
誤差逆伝播法では不要な再帰的処理を避ける事が出来る。既に行った計算結果を保持しているソースコードを抽出せよ。

```python
   # 出力層でのデルタ
    delta2 = functions.d_mean_squared_error(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)

 ## 試してみよう
    delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)
```
delta2に注目してみると、再利用されているのを確認できる。

・確認テスト4
![確認テスト逆伝搬.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/57a12490-f078-b6a8-dc6d-3367d7b97606.png)

[回答]
上から順に

```python
delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)
 grad['W1'] = np.dot(x.T, delta1)
```

・実装演習
誤差伝搬法のみ下記に記載。

```python
def backward(x, d, z1, y):
　　grad = {}
    W1, W2 = network['W1'], network['W2']
    b1, b2 = network['b1'], network['b2']
　　delta2 = functions.d_mean_squared_error(d, y)
  
    grad['b2'] = np.sum(delta2, axis=0)
   
    grad['W2'] = np.dot(z1.T, delta2)
   
   

   
    delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)
　　delta1 = delta1[np.newaxis, :]
    
    grad['b1'] = np.sum(delta1, axis=0)
    x = x[np.newaxis, :]
    
    grad['W1'] = np.dot(x.T, delta1)
    return grad
```


# 勾配消失問題

誤差伝搬法が下位層へと進むにつれて、勾配がゆるやかなカーブになってくる。そのため
勾配降下法による更新では下位層のパラメータでは変わらず、訓練は最適値へと変わっていかない。学習がうまくいかなかなる原因のひとつ。


勾配消失問題の解決策
・活性化関数の選択
→シグモイド関数は勾配消失問題を引き起こす代表的な活性化関数。
→ReLU関数は勾配消失問題の回避とスパース化に貢献する


・重みの初期値の設定
→重みの初期値設定としてXavier やHe があげられる。
a)Xavier 
重みの要素を、前の層のノード数の平方根で除算した値

b)He
重みの要素を、前の層のノード数の平方根で除算した値に対し√２をかけ合わせた値

・バッチ正規化
などがあげられる。


・確認テスト1
シグモイド関数を微分した時、入力値が０の時最大値をとる。その値として
正しい値を下記から選択せよ

(1)0.15
(2)0.25
(3)0.35
(4)0.45

[回答]

(2)0.25

・確認テスト2
重みの初期値に０を設定するとどのような問題が発生するか。簡潔に述べよ。

[回答]
学習の悪化。すべての重みの初期値を０にして伝播させると、同じ値が伝播してしまう。よって重みが同じように更新してしまい、表現の幅がせまくなる。

・確認テスト3
一般的に考えられるバッチ正規化の効果を2点挙げよ。

[回答]
より早く学習できることや、訓練データへの過剰適合を防ぐことができる。

・実装演習
シグモイド関数とReLU関数の違いを以下に表記する。

まずはシグモイド関数

```python
# データの読み込み
(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True, one_hot_label=True)

print("データ読み込み完了")

network = MultiLayerNet(input_size=784, hidden_size_list=[40, 20], output_size=10, activation='sigmoid', weight_init_std=0.01)

iters_num = 2000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    # 勾配
    grad = network.gradient(x_batch, d_batch)
    
    for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
        network.params[key] -= learning_rate * grad[key]
    
    loss = network.loss(x_batch, d_batch)
    train_loss_list.append(loss)
    
    if (i + 1) % plot_interval == 0:
        accr_test = network.accuracy(x_test, d_test)
        accuracies_test.append(accr_test)        
        accr_train = network.accuracy(x_batch, d_batch)
        accuracies_train.append(accr_train)

        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))
        

lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
# グラフの表示
plt.show()
```
![シグモイド関数.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/a81310e6-b755-3714-c43f-1933f6effd09.png)
シグモイド関数では、学習がうまく進まず勾配消失問題を引き起こしているのが確認できる。

つづけてReLU関数

```python
# データの読み込み
(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True, one_hot_label=True)

print("データ読み込み完了")

network = MultiLayerNet(input_size=784, hidden_size_list=[40, 20], output_size=10, activation='relu', weight_init_std=0.01)

iters_num = 2000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    # 勾配
    grad = network.gradient(x_batch, d_batch)
    
    for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
        network.params[key] -= learning_rate * grad[key]
    
    loss = network.loss(x_batch, d_batch)
    train_loss_list.append(loss)
    
    if (i + 1) % plot_interval == 0:
        accr_test = network.accuracy(x_test, d_test)
        accuracies_test.append(accr_test)        
        accr_train = network.accuracy(x_batch, d_batch)
        accuracies_train.append(accr_train)

        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))
        
        
lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
# グラフの表示
plt.show()
```
![ReLU.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/0d3300e5-572e-7ffb-41cd-41109b5e4038.png)

ReLU関数では学習がスムーズにいっているのが確認できる。


#学習率最適化手法
代表的な学習率最適化手法を下記に記載する。

1)モメンタム
誤差をパラメータで微分したものと学習率の積を減算した後、現在の重みに前回の重みを減算した値と慣性の積を加算する

```math
V_{t} =μV_{t-1}-\epsilon▽E
```

```math
W^{t+1}=W^{t}+V_{t}

```
μ：慣性

コードでの表記は次の通り。

```python
self.v[key] = self.momentum* self.v[key] -self.learning_rate* 
```

```python
grad[key]params[key] += self.v[key]S2)-143
```

2)AdaGrad
誤差をパラメータで微分したものと再定義した学習率の積を減算する
メリットとしては、勾配の緩やかな斜面に対して、最適値に近づける点にある。
また、鞍点問題を引きおこすことがあり。

3)RMSProp
誤差をパラメータで微分したものと再定義した学習率の積を減算する。
メリットとしては、局所的最適解にはならず、大域的最適解となる点やハイパーパラメータの調整が必要な場合が少ないことなどがあげられる。

4)Adam
・モメンタムの、過去の勾配の指数関数的減衰平均
・RMSPropの、過去の勾配の2乗の指数関数的減衰平均

メリットとしては、モメンタムおよびRMSPropのメリットを孕んだアルゴリズムである。

・確認テスト
モメンタム・AdaGrad・RMSPropの特徴をそれぞれ簡潔に説明せよ。

３つともパラメータ更新を効率的に行う最適化手法である。

①モメンタム
前回の更新の方向に慣性（モメンタム項）
をつけることによって学習を早めるテクニック。

②AdaGrad
誤差をパラメータで微分し、再定義した学習率の積を減算する手法。

③RMSProp
AdaGradでは、一度大きな勾配を経験すると、その後の学習率が相対的に低くなりすぎることが
ある。このデメリットを過去の勾配情報を忘却させていくという手法で問題を緩和した最適化手法である。

・実装演習

Momentumの実装を以下に記載する。

```python
# データの読み込み
(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True, one_hot_label=True)

print("データ読み込み完了")

# batch_normalizationの設定 =======================
# use_batchnorm = True
use_batchnorm = False
# ====================================================

network = MultiLayerNet(input_size=784, hidden_size_list=[40, 20], output_size=10, activation='sigmoid', weight_init_std=0.01,
                       use_batchnorm=use_batchnorm)

iters_num = 1000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    # 勾配
    grad = network.gradient(x_batch, d_batch)
    if i == 0:
        h = {}
    for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
        if i == 0:
            h[key] = np.full_like(network.params[key], 1e-4)
        else:
            h[key] += np.square(grad[key])
        network.params[key] -= learning_rate * grad[key] / (np.sqrt(h[key]))

        loss = network.loss(x_batch, d_batch)
        train_loss_list.append(loss)        
        
        
    if (i + 1) % plot_interval == 0:
        accr_test = network.accuracy(x_test, d_test)
        accuracies_test.append(accr_test)        
        accr_train = network.accuracy(x_batch, d_batch)
        accuracies_train.append(accr_train)
        
        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))
        
lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.show()
```

![test.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/fa730351-7fb2-a79f-d51a-2a6c4584cf7b.png)


# 過学習
学習データに過剰適合（正解率が高い）しているが、テストデートでは正解率が低い。
テスト誤差と訓練誤差において学習曲線が剥離していること。

※受験生を例にとって説明すると、問題集では正解率が高いが模試では正解率が低いことを指す。

原因としては、パラメータの数が多かったり、パラメータの値が適正でないこと等、
つまりネットワークの自由度（層数、ノード数、パラメータ値など）が高い。

・正則化
過学習を抑制する手法として正則化があげられる。
正則化とは、ネットワークの自由度を抑制すること。
正則化にはL1正則化（Lasso回帰）、L2正則化（Ridge回帰）、ドロップアウトがあげられる。

・確認テスト
下図について、L1正則化を示しているのはどちらか答えよ。
![L1,L２.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/c19d8f63-333a-f1f8-8983-418d1dbc186a.png)

[回答]
右のLasso回帰を指す。

・実装演習
まずは過学習になる現象について実装してみる。

```
import numpy as np
from collections import OrderedDict
from common import layers
from data.mnist import load_mnist
import matplotlib.pyplot as plt
from multi_layer_net import MultiLayerNet
from common import optimizer


(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True)

print("データ読み込み完了")

# 過学習を再現するために、学習データを削減
x_train = x_train[:300]
d_train = d_train[:300]

network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10)
optimizer = optimizer.SGD(learning_rate=0.01)

iters_num = 1000
train_size = x_train.shape[0]
batch_size = 100

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10


for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    grad = network.gradient(x_batch, d_batch)
    optimizer.update(network.params, grad)

    loss = network.loss(x_batch, d_batch)
    train_loss_list.append(loss)
        
    if (i+1) % plot_interval == 0:
        accr_train = network.accuracy(x_train, d_train)
        accr_test = network.accuracy(x_test, d_test)
        accuracies_train.append(accr_train)
        accuracies_test.append(accr_test)

        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))        

lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
# グラフの表示
plt.show()
```
![過学習.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/e9373129-d94f-a23b-3026-655c97e557a9.png)

テストデータの学習率があがっておらず、過学習が起こっているのを確認できた。
なのでL2正則化を実装してみる。

```python
from common import optimizer

(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True)

print("データ読み込み完了")

# 過学習を再現するために、学習データを削減
x_train = x_train[:300]
d_train = d_train[:300]


network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10)


iters_num = 1000
train_size = x_train.shape[0]
batch_size = 100
learning_rate=0.01

train_loss_list = []
accuracies_train = []
accuracies_test = []

plot_interval=10
hidden_layer_num = network.hidden_layer_num

# 正則化強度設定 ======================================
weight_decay_lambda = 0.1
# =================================================

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    d_batch = d_train[batch_mask]

    grad = network.gradient(x_batch, d_batch)
    weight_decay = 0
    
    for idx in range(1, hidden_layer_num+1):
        grad['W' + str(idx)] = network.layers['Affine' + str(idx)].dW + weight_decay_lambda * network.params['W' + str(idx)]
        grad['b' + str(idx)] = network.layers['Affine' + str(idx)].db
        network.params['W' + str(idx)] -= learning_rate * grad['W' + str(idx)]
        network.params['b' + str(idx)] -= learning_rate * grad['b' + str(idx)]        
        weight_decay += 0.5 * weight_decay_lambda * np.sqrt(np.sum(network.params['W' + str(idx)] ** 2))

    loss = network.loss(x_batch, d_batch) + weight_decay
    train_loss_list.append(loss)        
        
    if (i+1) % plot_interval == 0:
        accr_train = network.accuracy(x_train, d_train)
        accr_test = network.accuracy(x_test, d_test)
        accuracies_train.append(accr_train)
        accuracies_test.append(accr_test)
        
        print('Generation: ' + str(i+1) + '. 正答率(トレーニング) = ' + str(accr_train))
        print('                : ' + str(i+1) + '. 正答率(テスト) = ' + str(accr_test))               


lists = range(0, iters_num, plot_interval)
plt.plot(lists, accuracies_train, label="training set")
plt.plot(lists, accuracies_test,  label="test set")
plt.legend(loc="lower right")
plt.title("accuracy")
plt.xlabel("count")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
# グラフの表示
plt.show()
```

![L2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/8be354ab-0233-6838-f6b4-0bd183e12bde.png)

学習率が改善されたのを確認できた。


# 畳み込みニューラルネットワークの概要
CNNの構造について以下に記載する。

入力層（入力画像）→畳み込み層→畳み込み層→プーリング層→畳み込み層→畳み込み層→プーリング層→全結合層→出力層（出力画像）

３チャンネルの入力画像を例にとる。

![CNN.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/ecb2498c-3576-5a67-2958-d544d09f0977.png)

フィルターをずらしながら入力画像の処理を行っている。
まわりのピクセルとつながりを持ちながら入力結果を作っていくのが畳み込みニューラルネットワークの大きな特徴である。

・確認テスト
サイズ6×6の入力画像を、サイズ2×2のフィルタで畳み込んだ時の出力画像のサイズを答えよ。なおストライドとパディングは1とする。

[回答]
高さ、幅ともに、(6+2x1-2)+1 =7 



# 最新のCNN

画像認識コンテストで優勝したAlexNexについて今回とりあげる。
ネットワークデザインについて、８つのレイヤーが含まれており、最初の５つは畳み込み層であり、そのうちのいくつかにmax-pooling層が続き、最後の３つは全結合層である。
また、活性化関数にはReLU関数を使用している。
図を下記に示す。

![alexnet.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207209/7f66cf81-e166-688f-88ed-3167de7ac504.png)


# 参考図書
[ゼロから作るDeep Learning]
(https://www.oreilly.co.jp/books/9784873117584/)