無から始めるKeras 第1回

無から始める Keras のもくじは[こちら](http://qiita.com/Ishotihadus/items/6ecf5684c2cbaaa6a5ef)

# 無とは

Kerasの知識どころか、ニューラルネット、さらにはPythonすらもわからない状態ではじめるKeras。
Python3だけはインストールしてあるものとする（これは環境によって違うのでググってください）。

まずはともあれインストール。

```shell-session
$ sudo pip3 install tensorflow keras
```

そしてPythonを起動。

```shell-session
$ python3
```

対話型のほうがやりやすい気がする。

# 配列を作る

配列はNumPyで扱う。遅くないので。

```py3
import numpy as np
array = np.array([0.1,0.2,0.3])
```

配列が作れた。1行目はライブラリを読み込むので使う時は常に必要（それはそう）。

二次元も作れる。行列における行方向（横向き）が内側の配列になる。下なら

```math
\begin{pmatrix}0.1 & 0.2 & 0.3 \\ 0.4 & 0.6 & 0.8\end{pmatrix}
```

を表す。

```py3
array = np.array([[0.1,0.2,0.3], [0.4,0.6,0.8]])
```

零行列、すべての要素が1の行列、単位行列は以下の通り。`(a,b,c,...)` で配列の要素数を示せる。Python的にはタプル。

```py3
array = np.zeros((2,3))
array = np.ones((3,1))
array = np.identity(5) # sizeは(5,5)
```

ランダム行列も作っとこう。

```py3
array = np.random.rand(3,2) # 0以上1未満の一様分布
array = np.random.randn(5,4) # 平均0、分散1の正規分布
array = np.random.randint(0, 5, size=(2,3)) # 0以上5未満の離散一様分布
```

ここまでは練習。

# データセットを作る

学習をしてみたいので、とにかくデータセットを作ってみる。

```py3
data = np.random.rand(250,5)
labels = (np.sum(data, axis=1) > 2.5) * 1
```

1行目のデータは、5次元のデータを250個作っただけ。
2行目のラベルは、250個の各データに対して5次元の和をとり、それが2.5より大きいときに1となる（そうでないときは0となる）ような配列。

これを使って、適当な5次元の配列を入力したら、その和が2.5より大きいときに1と教えてくれるニューラルネットを作ろうという話。

# データセットを整形する

2クラスの出力があるので、実際にはワンホットであってほしい。
つまり、1つの（5次元）入力に対して出力は2次元で、入力の和が2.5以下だと `[1,0]` に、2.5より大きいと `[0,1]` になって欲しいというわけだ。

そういうようなラベル付けをするために、Kerasの機能を使う。importするときにログが吐かれるけどおおよそ気にしなくていいはず。

```py3
from keras.utils import np_utils
labels = np_utils.to_categorical(labels)
```

こうすると、`labels` は2次元の配列250個になる。

# ニューラルネットを作る

Sequentialはただ層を積み上げるだけの単純なモデル。1層前の出力をそのまま入力する感じ。ノード間にはすべてエッジを引く形（当然抜くこともできるが省略）。
今回は中間層1層（入力層・隠れ層・出力層）としてみる。

```py3
from keras.models import Sequential
from keras.layers import Dense, Activation
model = Sequential()
```

次に入力層―隠れ層を入れる。Denseというレイヤーをとりあえず使う。5個のノードからそれぞれ20本矢印が出てきて、次の層のノードが20個であることを示す。
ノード数は入力データの次元数と一致する必要がある（当然である）。

```py3
model.add(Dense(20, input_dim=5))
```

次は活性化関数を入れてみよう。20個のノードそれぞれに対して5つの数値が入ってくるが、その5つの数値の重み付け和（＋バイアス）を適当にとって最後に関数をかける。そのときの関数が活性化関数である。今回はランプ関数。

```py3
model.add(Activation('relu'))
```

この2つは `Dense(20, input_dim=5, activation='relu')` でまとめても同じだと思う。

次は隠れ層―出力層。20個のノードから（活性化関数が適用されたあと）それぞれ値がやってくる。出力は2次元で、ノードにやってきた20個の値に対して重み付き和とソフトマックス関数を適用する。カテゴリ判別にはソフトマックス関数がいいらしい。

```py3
model.add(Dense(2, activation='softmax'))
```

図にすると下みたいな感じ（20個もノードを書くのが面倒なので10個にした）。一般的なニューラルネットワークの図とは違うけど、説明用にアレンジしてみた。

本当はDenseもActivationもレイヤー（層）を表すのだが、なんとなく「つなぐもの」をイメージしたほうがわかりやすい気がした。

![名称未設定.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/78668/38fde25c-149b-5556-2384-9b6c7994c2f1.jpeg)

# コンパイル

学習の前に、コンパイルを行う。

1つめは最適化関数、2つめは損失関数、3つめは評価指標のリスト。とりあえずありがちなものを使う。

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

# いざ学習

`nb_epoch` は回数。`validation_split` は検証に使うデータの割合（全体のデータを学習に使わず、8割のみを学習に使って、残りの2割を評価に使う）。

```py3
model.fit(data, labels, nb_epoch=300, validation_split=0.2)
```

学習できたかな。

# 未知データの予測

実際に動いているか試す。

```py3
test = np.random.rand(200, 5)
predict = np.argmax(model.predict(test), axis=1)
real = (np.sum(test, axis=1) > 2.5) * 1
sum(predict == real) / 200.0
```

おおよそ98%くらいの精度で判別できている。まあこんな簡単な条件だし。
ちなみに学習を回さずに判別させると50%くらいになる。まあ適当にやって当たる確率は50%なので。

# 今回のプログラムまとめ

モデルを定義するときに同時にレイヤーも積み重ねている。

```py3
import numpy as np
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation

data = np.random.rand(250,5)
labels = np_utils.to_categorical((np.sum(data, axis=1) > 2.5) * 1)
model = Sequential([Dense(20, input_dim=5), Activation('relu'), Dense(2, activation='softmax')])
model.compile('rmsprop', 'categorical_crossentropy', metrics=['accuracy'])
model.fit(data, labels, nb_epoch=300, validation_split=0.2)

test = np.random.rand(200, 5)
predict = np.argmax(model.predict(test), axis=1)
real = (np.sum(test, axis=1) > 2.5) * 1
print(sum(predict == real) / 200.0)
```