kerasを使ってみよう

# はじめに
知人にKerasをおすすめするために、Kerasの書き方についてサンプルを参考にしながら今一度まとめて見ました。

間違えていたので修正しました。（5/3）
function → functional
ご指摘ありがとうございます。

# Kerasとは

以下公式からの抜粋です。
公式：https://keras.io/ja/
>Kerasは，Pythonで書かれた，TensorFlowまたはCNTK，Theano上で実行可能な高水準のニューラルネットワークライブラリです． Kerasは，迅速な実験を可能にすることに重点を置いて開発されました． アイデアから結果に到達するまでのリードタイムをできるだけ小さくすることが，良い研究をするための鍵になります．
https://keras.io/ja/

> どうしてこのライブラリにKerasという名前を付けたのですか？

> Keras (κέρας) はギリシア語で角を意味します．古代ギリシア文学およびラテン文学における文学上の想像がこの名前の由来です．最初にこの想像が見つかったのは_Odyssey_で，夢の神（Oneiroi，単数形 Oneiros）は，象牙の門を通って地上に訪れて偽りのビジョンで人々を騙す神と， 角の門を通って地上に訪れて起こるはずの未来を知らせる神とに分かれているそうです．これは κέρας （角）/ κραίνω （遂行）と ἐλέφας （象牙）/ ἐλεφαίρομαι （欺瞞）の似た響きを楽しむ言葉遊びです．

> Kerasは当初プロジェクトONEIROS (Open-ended Neuro-Electronic Intelligent Robot Operating System) の研究の一環として開発されました．

簡単に言うと、Tensorflowでもニューラルネットワーク実装できるけど、Tensorflowよりもっと簡単ハッピー！ということですね。

バックエンドにTensorflowしか使ったことないですが実際は、3つ使えるようです。
> 現在は，Kerasは3つのバックエンドが利用可能で，それはTensorFlowバックエンドとTheanoバックエンド，そしてCNTKバックエンドです．
>
> TensorFlow はGoogle, Inc.により開発されたオープンソースで，テンソルをシンボリックに操作ができるフレームワークです．
> Theano はモントリオール大学のLISA/MILA Labにより開発されたオープンソースで，テンソルをシンボリックに操作ができるフレームワークです．
> CNTK はMicrosoftによって開発された深層学習のためのcommercial-grade toolkitというオープンソースです．
> 将来的に，さらにバックエンドを追加する予定です．


## インストール
まず、Tensorflowが必要となります。pythonのパッケージ管理ツールであるpipを使って簡単にインストール出来ます。

```
pip3 install tensorflow
```

今回は、Ubuntu、python3を想定してます。GPUを使う場合や、OSやpythonのバージョンが異なる場合やanaconda、Dockerでのインストール方法も乗っているので、詳しくは公式サイトを参照してください。
公式：https://www.tensorflow.org/install/

Keras自体のインストールもpipで簡単に出来ます。

```
pip3 install keras
```


# サンプルプログラム
hello world的な存在である、mnistをやってみましょう。
手書きの6の数字の画像をニューラルネットに投げると、6です！と判定してくれるあれです。

28×28ピクセルの白黒手書き数字の画像のデータセットを使います。
これらの画像をニューラルネットに与え、0〜9のクラス分類を行います。

参考にするソースコードはこちらです。
https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py


コードを見ていきます。最初に、mnistのデータセットをとってきます。

```python
from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
```
データセットをとってくるのもkerasでできるんですね。簡単です。



次に、ニューラルネットに与えるために入出力を整形しています。

```python3
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

```

ニューラルネットのレイヤー毎に入力次元が決まっているので、それに合わせてnumpyで次元を合わせていきます。

次に、モデルを定義しています。

```python

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
```

modelに対して、使いたいレイヤーを追加していく感じです。簡単ですね。

まず、1行目で、モデルのインスタンスを生成します。2行目で、入力層を定義します。入力層の次元を定義するだけで、その後の層は、隠れ層の数を設定するだけです。ここの、input_shapeは意外と自由度の高い書き方ができるのでハマりポイントの一つかと思います。入力次元はRNNやCNNなどモデル毎に異なっているので調べましょう。Kerasは、日本語ドキュメントが充実しているので、大抵は公式のドキュメントに書いてあります。ただ、最新は英語のドキュメントしかないので、欲しい機能のドキュメントが日本語でなければ英語のドキュメントをのぞいて見ると実装されているかもしれません。

今回はクラス分類のためsoftmaxを使っていますが、活性化関数も、十分に実装されているかと思います。
活性化関数:https://keras.io/ja/activations/

ここで、Kerasのモデルの定義には2通りの方法があります。1つ目は、今回のサンプルで用いているSequentialモデルです。2つ目は、functional APIを用いたモデルです。

上記のサンプルをfunctional APIを使うと次のようにかけます。

```python

input_layer = Input(shape=(784,))
layer2 = Dense(512, activation='relu')(input_layer)
layer2 = Dropout(0.2)(layer2)
layer3 = Dense(512, activation='relu')(layer2)
layer3 = Dropout(0.2)(layer3)
output = Dense(num_classes, activation='softmax')(layer3)

model = Model(input_layer, output)
```

よく見るのは、サンプルの方のSequentialモデルだと思いますが、functional APIの書き方の方が入出力がわかりやすく、スッキリしていると思います。functional APIの書き方を用いると、複雑なモデルも構築できるようになるので、こちらの書き方に慣れておく方が良いかと思います。

では、サンプルコードに戻ります。
Kerasでは、簡単にモデルの構造を見ることができます。

```
model.summary()
```

と書くだけです。

実行すると次のように表示されます。

```
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense_1 (Dense)              (None, 512)               401920
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0
_________________________________________________________________
dense_2 (Dense)              (None, 512)               262656
_________________________________________________________________
dropout_2 (Dropout)          (None, 512)               0
_________________________________________________________________
dense_3 (Dense)              (None, 10)                5130
=================================================================
Total params: 669,706
Trainable params: 669,706
Non-trainable params: 0
_________________________________________________________________
```

レイヤーとそれぞれの出力次元、パラメタ数が確認できます。

次に、モデルのコンパイルを行います。

```python

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

損失関数と最適化アルゴリズムの設定はここで行います。それぞれ、十分に実装されています。
損失関数：https://keras.io/ja/losses/
最適化アルゴリズム：https://keras.io/ja/optimizers/


次は、実際に学習を行う部分です。

```python

history = model.fit(x_train, y_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test, y_test))
```

入力データ、教師データを引数に与えます。また、batch_sizeやepochsもここで設定します。簡単ですね。
fitの返り値を受け取ることで、学習時のlossやaccurasyを確認できます。


最後に、テストデータに対するスコアを計算します。

```python

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
```

実行すると、次のような結果が得られると思います。

```
Test loss: 0.116072395734
Test accuracy: 0.9827
```

長々と説明しましたが、コード自体は、50行ほどです。これだけでニューラルネットワークが実装できるのは素敵です。


# まとめ
Kerasの使い方を簡単にまとめてみました。ドキュメントが充実しているのが良い点かと思います。また、functional APIを使うことで複雑なネットワークも簡単に構築することもでき、損失関数なども自ら定義できるので、最近の論文で提案されたようなネットワークも自分で組もうと思えば組めるかと思います。個人的にはChainerをあまり使ったことがなく、Kerasとの具体的な比較ができなかったので、Chainerをもう少し使ってみて比較ができると良いかと思います。