【kerasの使い手必見】複数モデルを学習させるシステム作りました。

# 俺の思想世界
ほんとディープラーニングって手作業多いよな。。。

→ モデル作って実行、モデル作って実行、あーーー。めんどくさい

→ **モデルを複数作って後は自動化**したい。

→ 自動化したら優秀なモデルだけ保存する機能とかつけてみたり、、、。

気がつくと俺はemacsとterminalを開いていた。
そして、１時間ほどで完成いたしました。　その名も！

***Modeler! (モデラー)***

[ソースコードはこちら](https://github.com/wataoka/modeler)

# kerasの復習
kerasに使い慣れている人は読み飛ばして下さい。
## ◼️kerasコーディングの流れ
1. データを用意する
2. モデルを構築する
3. モデルに学習させる
4. モデルを評価する


### 1.データを用意する

```python3
from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
```

`(x_train, y_train), (x_test, y_test)`という構造を持ったタプルにデータを突っ込むことが多いです。

### 2.モデルを構築する

```python3
from keras.models import Sequential
from keras.layers import Dense

model = Sequential()
model.add(Dense(64, activation='relu', input_dim=784))
model.add(Dense(10, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
```

modelにlayerをadd
modelにlayerをadd
modelにlayerをadd
を繰り返します。

### 3.モデルに学習させる

```python
model.fit(x_train, y_train,
            batch_size=100,
            epochs=12,
            verbose=1)
```

ハイパーパラメータを設定してから学習を開始します。

### 4. モデルを評価する。

```python
score = model.evaluate(x_test, y_test)
print(score[0])
print(score[1])
```

score[0]がloss
score[0]がaccuracyです。

# Modelerのできること
　さっき思いついてさっき作ったものなので、機能はまだまだ少ないです。「こんな機能があれば嬉しい！」みたいなものがあればコメント下さい。作れたら作ります。(大阪人)

- 複数モデルを順番に自動で学習してくれる。
- 優秀な順番にモデルをn個保存してくれる。(nは自由)

# Modelerの使い方
　まずは、[僕のGithub](https://github.com/wataoka/modeler)からクローンでもダウンロードでもコピペでもなんでもいいので僕の作った`modeler.py`をあなたのkerasプログラムと同じディレクトリに置いて下さい。


## ❶ Modelerオブジェクトの生成

```python
modeler = Modeler()
```

当然これだけ。

## ❷ 複数モデルをModelerに登録

```python
modeler.add(model1)
modeler.add(model2)
modeler.add(model3)
```

kerasコーディングに似せてModelerにmodelをaddして登録していく形にしました。
覚えやすくていいでしょ。

## ❸ 学習開始

```python
modeler.start(data)
```

これだけ
覚えやすいでしょ！

※ dataってのは(x_train, y_train), (x_test, y_test)の構造をしたタプルのことです。

## ❹ 保存
```python
modeler.save()
```

これだけ！！！
覚えやすい！！！

さて、どうですか。
使いたくなりませんか？

ここまでで紹介した使い方ですと、多くのパラメータが初期設定のままになっています。(epoch数とかbatch数とか)

それらを設定する方法など、詳細説明を下に続けます。

# 詳細用法
Modulerクラスの関数一覧

### ◆ init
Modelerオブジェクトの初期化を行う。空のmodelsディクショナリを生成するだけ。

- 引数
  - 無し
- 返り値
  - 無し

```python
def __init__(self):
    """
    modelsディクショナリについて
    key: model (modelオブジェクト)
    value: acc (float)
    """
    self.models = {}
```

### ◆ add
modelsディクショナリにmodelを追加する。

- 引数
  - model (kerasのモデルオブジェクト)
- 返り値
  - 無し

```python
def add(self, model):
    self.models[model] = 0.0
```

### ◆ start
登録されたmodelオブジェクト達の学習を順番に進めていく。

- 引数
 - `data` : (x_train, y_train), (x_test, y_test)という構造のタプル
 - `batch_size` : バッチサイズ, int
 - `epochs` : エポックの回数, int
 - `verbose` : 途中出力の設定(1がおすすめ), int
- 返り値
  - 無し

```python
def start(self, data, batch_size=128, epochs=500, verbose=1):

    (x_train, y_train), (x_test, y_test) = data

    for model in self.models:
        model.summary()
        model.fit(x_train, y_train,
                  batch_size=batch_size,
                  epochs=epochs,
                  verbose=verbose)
        self.models[model] = model.evaluate(x_test, y_test)[1]
```

### ◆ save
優秀な順番にモデルを保存する。
デフォルトでは、カレントディレクトリに`models`ディレクトリを作成し、その中にモデルを保存する設定になっています。

- 引数
  - models_dir: 保存するディレクトリ, string
  - n_save: 保存するモデルの数, int
- 返り値
  - 無し
    

```python
def save(self, models_dir="./models/", n_save=1):


    models = OrderedDict(sorted(self.models.items(), key=lambda x:x[1], reverse=True))

    if not os.path.exists(models_dir):
        os.mkdir(models_dir)

    for n, model in enumerate(models):
        if n < n_save:
            model.save(models_dir + "model_" + str(n) + ".h5")
        else:
            break
```



# 使用例
[僕のGithub](https://github.com/wataoka/modeler)にも用意しました`sample.py`で使い方を見ていきましょう。

## 各種インポート

```python
from keras.datasets import mnist
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense

from modeler import Modeler
```

当然ですが、
`from modeler import Modeler`
を忘れないでね

## mnistのデータをロード

```python
def load_data():

    (x_train, y_train), (x_test, y_test) = mnist.load_data()

    x_train = x_train.reshape(60000, 784)
    x_test = x_test.reshape(10000, 784)
    x_train = x_train.astype('float32') / 255
    x_test = x_test.astype('float32') / 255
    y_train = to_categorical(y_train, 10)
    y_test = to_categorical(y_test, 10)

    return (x_train, y_train), (x_test, y_test)
```

## モデルを三つ用意する

```python
def generate_models():
    model1 = Sequential()
    model1.add(Dense(64, activation='relu', input_dim=784))
    model1.add(Dense(10, activation='softmax'))
    model1.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

    model2 = Sequential()
    model2.add(Dense(128, activation='relu', input_dim=784))
    model2.add(Dense(10, activation='softmax'))
    model2.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

    model3 = Sequential()
    model3.add(Dense(256, activation='relu', input_dim=784))
    model3.add(Dense(10, activation='softmax'))
    model3.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

    return (model1, model2, model3)
```

## 使ってみる。

```python
if __name__ == "__main__":

    data = load_data()

    (model1, model2, model3)  = generate_models()

    modeler = Modeler()
    modeler.add(model1)
    modeler.add(model2)
    modeler.add(model3)
    modeler.start(data,
                  epochs=12)
    modeler.save(n_save=1)
```

<img width="780" alt="スクリーンショット 2018-06-21 0.12.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/221435/77bab5e4-2004-6206-7379-144c368f92ad.png">

しっかりと三つのモデルを順番に実行してくれています。

そして、今回の設定では最も優秀なモデルのみを保存する設定にしていましたので、

<img width="647" alt="スクリーンショット 2018-06-21 0.13.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/221435/4fdb116f-ca5e-295e-abe7-030204450623.png">

このように、modelsディレクトリの中に一つだけ保存されています。


皆さんも、こんな感じで自分なりにアレンジしたkerasを楽しんでみて下さい。
そして、よければ使ってみて下さい。
最後まで読んでいただきありがとうございました！！！