TensorflowでMNISTデータ認識＋多層ニューラルネット＋yamlファイルで全設定

# はじめに
[前々回](http://qiita.com/WaterIsland/items/7438dcbd4667748f1100)とか[前回](http://qiita.com/WaterIsland/items/506e42cd45862b0b9174)でTensorflowでMNISTデータ認識を多層ニューラルネット（とは言っても入力層もカウントして３層）を試してきた。
AutoEncoder か畳み込みネット(Convolutional Neural Net)を試そうと考えたが、毎回の設定をいじるのが面倒臭い。後々の~~ぐうたら~~効率化を図りたい。というわけで、 yaml でネットワークの内容をごっそり書けるようにすれば楽チンじゃないか！と思い立ち、作ってみた。
まだ多層ニューラルネットしか対応してないけどね。今回はそんな内容である。


# ソース
[MultiLayerNetwork.py](https://github.com/WaterIsland/DLStudy/blob/master/tensorflow/source/mine/mnist/MultiLayerNetwork.py)：調子に乗ってクラス化したソース
[YamlDumper.py](https://github.com/WaterIsland/DLStudy/blob/master/tensorflow/source/mine/mnist/YamlDumper.py)：yaml ファイルを読み込むクラス（適当作成物）
[3Layer-NN.yaml](https://github.com/WaterIsland/DLStudy/blob/master/tensorflow/source/mine/mnist/3Layer-NN.yaml)：３層のニューラルネット用ファイル
[4Layer-NN.yaml](https://github.com/WaterIsland/DLStudy/blob/master/tensorflow/source/mine/mnist/4Layer-NN.yaml)：４層のニューラルネット用ファイル


# 実装の概要
MultiLayerNetwork.py を実行すれば動作する。
yamlファイルを inference、loss、training で読み込んでいる。アドホックな手順なので割愛する。

3Layer-NN.yaml とか、4Layer-NN.yamlとか、構造はシンプルにしたつもりだ。
簡単に説明すると、
1. 「network」で、層の数や各部の名称を指定

```yaml:3Layer-NN.yaml
#####
## Network Parameters
#####
network:
    layer_num: 3 # --> 入力層も含めての層の数
    scope_name: # --> Tensorboard に表示する名前の指定
        layer1: 
            base_name: input
            output_name: x # -->入力層だけこの名前を使う。他の層は後述の activation を使う。
        layer1-2: 
            weight_name: W1
            bias_name: b1
        layer2: 
            base_name: hidden
            ## output_name: y1 # no use
        layer2-3: 
            weight_name: W2
            bias_name: b2
        layer3: 
            base_name: output
            ## output_name: y2 # no use
```

2. 「inference」で、ニューロン素子数や活性化関数や荷重やバイアスの初期化パラメタを指定

```yaml:3Layer-NN.yaml
#####
## Inference Parameters
#####
inference:
    node_number: # --> 各層のニューロン素子数
        layer1: 784
        layer2: 100
        layer3: 10
    activation:  # --> 各層の活性化関数
        layer1: none  # --> 現在は入力層の設定は無視するけど、念のため。
        layer2: relu
        layer3: softmax
        ## use following activation --> ここに書いてる活性化関数が使える。
        ## layerN: relu
        ## layerN: relu6
        ## layerN: elu
        ## layerN: softplus
        ## layerN: softsign
        ## layerN: sigmoid
        ## layerN: tanh
        ## layerN: softmax        
    initialize: # --> 各層間の結合やバイアスの初期化条件
        layer1-2: 
            weight_param:
                mean: 0   # --> dev とペアで使う
                dev: 0.01 # --> mean とペアで使う
                ## use following parameters in any other; weight_param and bias_param. --> ここに書いてるパラメタが使える。
                ## const shouldn't use to weights --> 荷重を constant にすると、学習ができない。
                ## mean: 0.1  # mean
                ## dev: 0.01  # deviation
                ## const: 0.1 # const value
            bias_param:
                const: 0.1 # --> const（定数）は単品で使う。
#                mean: 0
#                dev: 0.01
        layer2-3: 
            weight_param:
                mean: 0
                dev: 0.01
            bias_param:
                const: 0.1
#                mean: 0
#                dev: 0.01
```

3. 「loss」で、損失関数を指定

```yaml:3Layer-NN.yaml
#####
## Loss Parameters
#####                
loss: 
    function: crossentoropy # --> 損失関数
    ## use following functions --> ここに書いている損失関数が使える。
    ## function: crossentoropy
    ## function: logistic
    ## function: mse
```

4. 「training」で、学習法や学習率や最適化条件を指定

```yaml:3Layer-NN.yaml
#####
## Training Parameters
#####
training:
    function: GradientDescentOptimizer # --> 学習法
    ## use following functions --> ここに書いている学習法が使える。
    ## function: GradientDescentOptimizer
    eta: 0.1 # --> 学習率
    optimization: minimize # --> 学習の最適化条件
    ## use following optimization --> ここに書いている最適化条件が使える。
    ## optimization: minimize
```

# 実行環境
ざっくり以下の環境。
・Mac OS X 10.10.5
・Python 3.5.1
・virtualenv
・IPython
・PyYAML (3.12)


# 処理内容（特筆すべき処理）

```py:MultiLayerNetwork.py
obj = MultiLayerNetwork(fname='3Layer-NN.yaml')
# obj = MultiLayerNetwork(fname='4Layer-NN.yaml')
```

の２箇所のコメントアウトを入れ替えれば、３層と４層のニューラルネットが切り替わる。
今回も Graph を出力するので、[前回と同様のコマンドを入力し、](http://qiita.com/WaterIsland/items/506e42cd45862b0b9174#処理結果inspectしよう)Tensorboard で確認しよう。


学習時に、以下の accuracy を表示している。
1.validationデータ
2.testデータ
なお、本来の学習手法では、学習時に test データの提示をしないことに注意してほしい。（今回はお試しで表示している。そこに注意。）
提示しているデータは、ランダムサンプリングした、それぞれ100個ずつである。
その処理は以下に該当する。

```py:MultiLayerNetwork.py
if step % 20 == 0:
    # output summary to graph
    summary_writer.add_summary(summary_str, step)

    # validation data's accuracy
    validation_data_accuracy = obj.get_accuracy(
                    mnist.validation.images, 
                    mnist.validation.labels,
                    len(mnist.validation.images), 
                    100)

    # test data's accuracy
    test_data_accuracy = obj.get_accuracy(
                    mnist.test.images, 
                    mnist.test.labels,
                    len(mnist.test.images), 
                    100)

    print(
          "Train Step:[%4d], Accuracy[training : %.3f, validation : %.3f, test : %.3f], Cost[%2.3f]"
          % (step, accuracy, validation_data_accuracy, test_data_accuracy, cost)
    )
```