「ゼロから作るDeep Learning」自習メモ（その９）MultiLayerNet クラス

「ゼロから作るDeep Learning」(斎藤 康毅　著　オライリー・ジャパン刊)を読んでいる時に、参照したサイト等をメモしていきます。　[その８](https://qiita.com/slow_learner/items/d770bc712c96f0ec3b69) ←　→[その１０](https://qiita.com/slow_learner/items/cfca161fb2fb05216a74)

５章でニューラルネットワークの構成要素をレイヤとして実装し、６章でそれを使っています。
個々のレイヤについては５章で説明がありますが、実装した　MultiLayerNet クラスは、本の中では説明されていません。ソースは、フォルダcommon　の　multi_layer_net.py　にあります。

ということで、MultiLayerNet クラスの中身を見ていきます。

####6.1.8 MNIST データセットによる更新手法の比較　で使っているソースコード
ch06/optimizer_compare_mnist.py　でMultiLayerNet クラスを参照しています。

```python
# coding: utf-8
import os
import sys
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from common.optimizer import *


# 0:MNISTデータの読み込み==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000


# 1:実験の設定==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()

networks = {}
train_loss = {}
for key in optimizers.keys():
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100, 100, 100],
        output_size=10)
    train_loss[key] = []    


# 2:訓練の開始==========
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    for key in optimizers.keys():
        grads = networks[key].gradient(x_batch, t_batch)
        optimizers[key].update(networks[key].params, grads)
    
        loss = networks[key].loss(x_batch, t_batch)
        train_loss[key].append(loss)
```
MNISTデータセットを使うので、
input_size=784　　　入力は784 列（元は28 × 28）の画像データ
output_size=10　　　出力は０～９のどれであるかの予測確率
hidden_size_list=[100, 100, 100, 100]　隠れ層が４層あり、ニューロンの数が各１００個
そして
batch_size ミニバッチのサイズ（入力データの行数）が 128

この設定で全結合による多層ニューラルネットワークを作成するから、
こんな感じで、配列が作られる。

![w6-a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/132cfd43-e3a5-b406-b181-d10f6c73668b.jpeg)


以下、networksオブジェクトの中にある配列やオブジェクトを参照したときのものです。

```python
networks
```
>{'SGD': common.multi_layer_net.MultiLayerNet at 0x8800d50,
 'Momentum': common.multi_layer_net.MultiLayerNet at 0x8800a50,
 'AdaGrad': common.multi_layer_net.MultiLayerNet at 0x8800710,
 'Adam': common.multi_layer_net.MultiLayerNet at 0x88003d0}

```python
networks['SGD']
```
>common.multi_layer_net.MultiLayerNet at 0x8800d50

```python
networks['SGD'].layers
```
>OrderedDict([('Affine1', common.layers.Affine at 0x8800c30),
             ('Activation_function1', common.layers.Relu at 0x8800c70),
             ('Affine2', common.layers.Affine at 0x8800bf0),
             ('Activation_function2', common.layers.Relu at 0x8800bd0),
             ('Affine3', common.layers.Affine at 0x8800b90),
             ('Activation_function3', common.layers.Relu at 0x8800b70),
             ('Affine4', common.layers.Affine at 0x8800ab0),
             ('Activation_function4', common.layers.Relu at 0x8800b30),
             ('Affine5', common.layers.Affine at 0x8800af0)])




```python
networks['SGD'].layers['Affine1'].x
```
>array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]], dtype=float32)

```python
networks['SGD'].layers['Affine1'].x.shape
```
>(128, 784)

```python
networks['SGD'].layers['Affine1'].W
```
>array([[-0.04430735, -0.00916858, -0.05385046, ..., -0.01356, 0.0366878, -0.04629992],
       [-0.0974915 ,  0.01896   ,  0.0016755 , ...,  0.00820512, -0.01012246, -0.04869024],
       ...,
       [ 0.03065034, -0.02653425, -0.00433941, ..., -0.06933382, 0.03986452, 0.06821553],
       [ 0.01673732,  0.04850334, -0.0291053 , ..., -0.05045292, 0.00599257, 0.08265754]])

```python
networks['SGD'].layers['Affine1'].W.shape
```
>(784, 100)

```python
networks['SGD'].layers['Affine1'].b
```
>array([ 0.01646891,  0.01467293,  0.02892796,  0.02414651,  0.02259769,
       -0.00919552, -0.01567924,  0.0039934 ,  0.00693527,  0.03932801,
       ..., 
       -0.00536202,  0.00508444,  0.00204647,  0.01040528,  0.00355356,
       -0.00960685,  0.06204312,  0.02886584,  0.06678846,  0.0186539 ])

```python
networks['SGD'].layers['Affine1'].b.shape
```
>(100,)

```python
networks['SGD'].layers['Activation_function1']
```
>common.layers.Relu at 0x8800c70

```python
networks['SGD'].layers['Affine2'].x.shape
```
>(128, 100)

```python
networks['SGD'].layers['Affine2'].W.shape
```
>(100, 100)

```python
networks['SGD'].layers['Affine2'].b.shape
```
>(100,)

```python
networks['SGD'].layers['Activation_function2']
```
>common.layers.Relu at 0x8800bd0

```python
networks['SGD'].layers['Affine3'].x.shape
```
>(128, 100)

```python
networks['SGD'].layers['Affine3'].W.shape
```
>(100, 100)

```python
networks['SGD'].layers['Affine3'].b.shape
```
>(100,)

```python
networks['SGD'].layers['Activation_function3']
```
>common.layers.Relu at 0x8800b70

```python
networks['SGD'].layers['Affine4'].x.shape
```
>(128, 100)


```python
networks['SGD'].layers['Affine4'].W.shape
```
>(100, 100)

```python
networks['SGD'].layers['Affine4'].b.shape
```
>(100,)

```python
networks['SGD'].layers['Activation_function4']
```
>common.layers.Relu at 0x8800b30

指定した中間層の数は４だが、その後に出力層として５番目の層を作っている。

```python
networks['SGD'].layers['Affine5'].x.shape
```
>(128, 100)


```python
networks['SGD'].layers['Affine5'].W.shape
```
>(100, 10)

```python
networks['SGD'].layers['Affine5'].b.shape
```
>(10,)

出力層の活性化関数は、last_layer に定義されている。
ここではソフトマックス関数を使っている。

```python
networks['SGD'].last_layer
```
>common.layers.SoftmaxWithLoss at 0x8800770

```python
networks['SGD'].last_layer.y
```
>array([[2.08438091e-05, 2.66555051e-09, 1.29436456e-03, ...,
        1.83391350e-07, 9.98317338e-01, 6.77137764e-05],
       [5.68871828e-04, 1.59787427e-06, 3.60265866e-03, ...,
        7.25385216e-05, 1.80220134e-03, 4.95014520e-02],
       ...,
       [3.01731618e-03, 5.57601184e-03, 1.40908372e-02, ...,
        8.49627989e-02, 5.44208078e-03, 2.32114245e-01],
       [9.82201047e-07, 3.01213101e-07, 1.05657504e-03, ...,
        1.03584551e-05, 9.92242677e-01, 5.06642654e-03]])

```python
networks['SGD'].last_layer.y.shape
```
>(128, 10)

####学習結果でテストしてみた　
>P177
この実験では、5 層のニューラルネットワークで、各層100 個のニューロンを持つ
ネットワークを対象にしました。また、活性化関数としてReLU を使用しました。
図6-9 の結果を見ると、SGD よりも他の手法が速く学習できていることが分か
ります。残り3 つの手法は同じように学習が行われているようです。よく見ると
AdaGrad の学習が少しだけ速く行われているようです。この実験の注意点として
は、学習係数のハイパーパラメータや、ニューラルネットワークの構造（何層の深さ
か、など）によって結果は変化するということです。ただし、一般にSGD よりも他
の3 つの手法のほうが速く学習でき、時には最終的な認識性能も高くなります。

ということなので、テストデータで認識性能の違いを調べて見た。

```python
# テストデータで評価
x = x_test
t = t_test

for key in optimizers.keys():
    network = networks[key]

    y = network.predict(x)

    accuracy_cnt = 0
    for i in range(len(x)):
        p= np.argmax(y[i])
        if p == t[i]:
            accuracy_cnt += 1

    print(key + " Accuracy:" + str(float(accuracy_cnt) / len(x))) 
```
>SGD Accuracy:0.934
Momentum Accuracy:0.9676
AdaGrad Accuracy:0.97
Adam Accuracy:0.9701

確かに、SGDの認識率は低いようです。

####ミニバッチの回数を2000から5000に変えて学習し、テストしてみたら、こうなりました。

```python
max_iterations = 5000
```
>SGD Accuracy:0.9557
Momentum Accuracy:0.9754
AdaGrad Accuracy:0.9755
Adam Accuracy:0.9752

回数を増やすと、４つとも認識率が上がりました。SGDも上がりましたが、2000回のときの他の手法よりも低いままです。

####中間層を２つに減らして、３層のニューラルネットで学習してみた。

```python
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100],
        output_size=10)
```
>SGD Accuracy:0.922
Momentum Accuracy:0.9633
AdaGrad Accuracy:0.9682
Adam Accuracy:0.9701

４つとも認識率が１％程度悪くなっている。

####中間層を８つに増やして、９層のニューラルネットで学習してみた。

```python
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100, 100, 100],
        output_size=10)
```
>SGD Accuracy:0.9479
Momentum Accuracy:0.9656
AdaGrad Accuracy:0.9692
Adam Accuracy:0.9701

SGDの認識率は上がりましたが、他は同じか少し悪くなってます。
層を増やすことで認識率が上がった、というよりは、学習の速度が速くなったと考えたほうがいいのかも？

####中間層のニューロンの数を50に減らしてみた

```python
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[50, 50, 50, 50],
        output_size=10)
```
>SGD Accuracy:0.9275
Momentum Accuracy:0.9636
AdaGrad Accuracy:0.962
Adam Accuracy:0.9687

####中間層のニューロンの数を200に増やしてみた

```python
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[200, 200, 200, 200],
        output_size=10)
```
>SGD Accuracy:0.9372
Momentum Accuracy:0.9724
AdaGrad Accuracy:0.9775
Adam Accuracy:0.9753


[その８](https://qiita.com/slow_learner/items/d770bc712c96f0ec3b69) ←　→[その１０](https://qiita.com/slow_learner/items/cfca161fb2fb05216a74)

[読めない用語集](https://qiita.com/slow_learner/items/03eb3367119e98b5a22c)