tiny-dnnを用いたIrisデータセットの学習

C++の深層学習用フレームワークであるtiny-dnnを用いて、Pythonのsklearnで提供されているirisのデータセットを学習させました。   

# まとめ
* tiny-dnnを用いてsklearnで提供されているirisのデータセットを学習させるコードを実装。
    * コードは[GitHub](https://github.com/Surpris/TestTinyDNN)で公開。
* tiny-dnnはKerasのような感覚で使いやすい。

## 環境
* Windows 10 Pro (64 bit) Version 1607
* Intel Core i5-3317U (1.70 GHz&times;2), RAM 4 GB
* Visual Studio 2017 Community
* tiny-dnnとsklearnを利用

# 背景
これまでPythonをよく利用してきたこともあり、Tensowflow, sklearn, Kerasあたりを使ってきました。
とある事情によりc++で、しかもx86環境で深層学習を扱う必要が生じました。
c++での深層学習フレームワークを探したところ、Microsoft社の[CNTK](https://docs.microsoft.com/en-us/cognitive-toolkit/), Cで書かれた[darknet](https://pjreddie.com/darknet/), そして[tiny-dnn](https://github.com/tiny-dnn/tiny-dnn)あたりがよさそうだということが分かりました。
それぞれについての検討状況は次の通りであり、今回はtiny-dnnを利用することにしました。   

* CNTK：2017/06/18 (Sun.) 現在、Visual Studio 2015 (c++14)のx64環境でしか動かないようである。
    * VS2017でもv140のツールセットをインストールすれば動く？いずれにせよx86では動かない模様。
* tiny-dnn：x86でも動作する。
* darknet：tiny-dnnがx86環境で動作することが判明したため未検討。  

## tiny-dnnについて
tiny-dnnはC++のx86/x64環境で利用できる深層学習フレームワークの一つです。
詳細や導入方法は[Original authorの方に紹介されています](http://qiita.com/nyanp/items/11c6bb6fb539486c5069)のでここでは割愛させていただきます。
ほかには[実装ノート](https://github.com/tiny-dnn/tiny-dnn/wiki/%E5%AE%9F%E8%A3%85%E3%83%8E%E3%83%BC%E3%83%88)（バージョンが古いようですが、分かりやすいです。）や[Documentation](http://tiny-dnn.readthedocs.io/en/latest/)が参考になります。
Qiitaでは『[FPGAでDeep Learningしてみる](http://qiita.com/ykshr/items/6c8cff881a200a781dc3#_reference-b811b282f8eae6cc82fc)』という報告があり、こちらではBNN-PYNQというtiny-dnnを利用したプロジェクトが利用されています。   

# コードの実装
コードは[GitHub](https://github.com/Surpris/TestTinyDNN)で公開しています。
2017/06/18 (Sun.) 時点での実装ですが、関数`main.cpp\main(void)`内で関数`dnn_iris(size_t batch_size, size_t epoch)`が実行されています。
この関数の内容は次の通りです。

1. 関数`load_iris_vec_t`でirisのデータセット（プロジェクト内では`.\\data\\iris.csv`）を読み込み、特徴量`X`とラベル`y`に分ける。
1. 関数`split_train_data`で、読み込んだirisのデータセットを学習データとテストデータに分ける。
1. モデルを定義する。今回は入力層、中間層、出力層の三層パーセプトロンとした。

    ```
    network<sequential> model;
    size_t n_neural = 100;
    model << fc(X[0].size(), n_neural) << activation::tanh()
          << fc(n_neural, y[0].size()) << activation::softmax();
    ```

1. モデルを次のように訓練する。

    ```
    adagrad opt;
    model.train<cross_entropy_multiclass>(opt, X_train, y_train, 
    batch_size, epoch);
    ```

1. 訓練されたモデルを用いてテストデータを分類する。そのときのlossとaccuracyを計算する。

テストデータとして読み込ませている`iris.csv`には、`sklearn.datasets.load_iris`で得られるデータセットの`X`と`y`が次の形式で保存されています。

```
// X_k (k=1,2,3,4): 特徴量
// y: ラベル
X_1, X_2, X_3, X_4, y
5.1, 3.5, 1.4, 0.2, 0
4.9,   3, 1.4, 0.2, 0
4.7, 3.2, 1.3, 0.2, 0
4.6, 3.1, 1.5, 0.2, 0
  5, 3.6, 1.4, 0.2, 0
5.4, 3.9, 1.7, 0.4, 0
...
```

## エポック数を変えて学習させた結果
試しにバッチ数を10に固定し、エポック数を10～100で変化させたときのloss、accuracy、訓練時間を調べてみました。その結果を次に示します。

```
Batch_size, Epoch, Elapsed time of training, Loss, Accuracy
10,  10,  3.95 sec, 92.2440, 0.6944
10,  20,  7.03 sec, 65.5258, 0.6944
10,  30, 10.86 sec, 62.9554, 0.7500
10,  40, 14.84 sec, 51.8333, 0.8889
10,  50, 18.56 sec, 52.2328, 0.8889
10,  60, 22.28 sec, 47.6374, 0.9167
10,  70, 27.04 sec, 46.4205, 0.9167
10,  80, 30.26 sec, 43.7856, 0.9167
10,  90, 35.74 sec, 36.4594, 0.9167
10, 100, 38.84 sec, 34.6639, 0.9444
```

# 今後やってみたいこと
* CSVファイルを読み込む関数を用意しているので、天気予報のデータや株価などほかのデータも学習させてみる。
* modelの保存・読み込みを行う関数が提供されているのでそれを使ってみる。
* x86のDLLにして外部から利用できるようにしてみる。
* などなど

# 参考サイト
* [The Microsoft Cognitive Toolkit | Microsoft Docs](https://docs.microsoft.com/en-us/cognitive-toolkit/)
* [Darknet: Open Source Neural Networks in C](https://pjreddie.com/darknet/)
* [tiny-dnn/tiny-dnn: header only, dependency-free deep learning framework in C++11](https://github.com/tiny-dnn/tiny-dnn)
* [C++ヘッダだけでDeep Learning、tiny-dnnの紹介 - Qiita](http://qiita.com/nyanp/items/11c6bb6fb539486c5069)
* [実装ノート · tiny-dnn/tiny-dnn Wiki · GitHub](https://github.com/tiny-dnn/tiny-dnn/wiki/%E5%AE%9F%E8%A3%85%E3%83%8E%E3%83%BC%E3%83%88)
* [tiny-dnn documentations — tiny-dnn 1.0.0a1 documentation](http://tiny-dnn.readthedocs.io/en/latest/)
* [FPGAでDeep Learningしてみる - Qiita](http://qiita.com/ykshr/items/6c8cff881a200a781dc3#_reference-b811b282f8eae6cc82fc)