無から始める Keras のもくじはこちら
無とは
Kerasの知識どころか、ニューラルネット、さらにはPythonすらもわからない状態ではじめるKeras。
Python3だけはインストールしてあるものとする(これは環境によって違うのでググってください)。
まずはともあれインストール。
$ sudo pip3 install tensorflow keras
そしてPythonを起動。
$ python3
対話型のほうがやりやすい気がする。
配列を作る
配列はNumPyで扱う。遅くないので。
import numpy as np
array = np.array([0.1,0.2,0.3])
配列が作れた。1行目はライブラリを読み込むので使う時は常に必要(それはそう)。
二次元も作れる。行列における行方向(横向き)が内側の配列になる。下なら
\begin{pmatrix}0.1 & 0.2 & 0.3 \\ 0.4 & 0.6 & 0.8\end{pmatrix}
を表す。
array = np.array([[0.1,0.2,0.3], [0.4,0.6,0.8]])
零行列、すべての要素が1の行列、単位行列は以下の通り。(a,b,c,...)
で配列の要素数を示せる。Python的にはタプル。
array = np.zeros((2,3))
array = np.ones((3,1))
array = np.identity(5) # sizeは(5,5)
ランダム行列も作っとこう。
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未満の離散一様分布
ここまでは練習。
データセットを作る
学習をしてみたいので、とにかくデータセットを作ってみる。
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するときにログが吐かれるけどおおよそ気にしなくていいはず。
from keras.utils import np_utils
labels = np_utils.to_categorical(labels)
こうすると、labels
は2次元の配列250個になる。
ニューラルネットを作る
Sequentialはただ層を積み上げるだけの単純なモデル。1層前の出力をそのまま入力する感じ。ノード間にはすべてエッジを引く形(当然抜くこともできるが省略)。
今回は中間層1層(入力層・隠れ層・出力層)としてみる。
from keras.models import Sequential
from keras.layers import Dense, Activation
model = Sequential()
次に入力層―隠れ層を入れる。Denseというレイヤーをとりあえず使う。5個のノードからそれぞれ20本矢印が出てきて、次の層のノードが20個であることを示す。
ノード数は入力データの次元数と一致する必要がある(当然である)。
model.add(Dense(20, input_dim=5))
次は活性化関数を入れてみよう。20個のノードそれぞれに対して5つの数値が入ってくるが、その5つの数値の重み付け和(+バイアス)を適当にとって最後に関数をかける。そのときの関数が活性化関数である。今回はランプ関数。
model.add(Activation('relu'))
この2つは Dense(20, input_dim=5, activation='relu')
でまとめても同じだと思う。
次は隠れ層―出力層。20個のノードから(活性化関数が適用されたあと)それぞれ値がやってくる。出力は2次元で、ノードにやってきた20個の値に対して重み付き和とソフトマックス関数を適用する。カテゴリ判別にはソフトマックス関数がいいらしい。
model.add(Dense(2, activation='softmax'))
図にすると下みたいな感じ(20個もノードを書くのが面倒なので10個にした)。一般的なニューラルネットワークの図とは違うけど、説明用にアレンジしてみた。
本当はDenseもActivationもレイヤー(層)を表すのだが、なんとなく「つなぐもの」をイメージしたほうがわかりやすい気がした。
コンパイル
学習の前に、コンパイルを行う。
1つめは最適化関数、2つめは損失関数、3つめは評価指標のリスト。とりあえずありがちなものを使う。
model.compile('rmsprop', 'categorical_crossentropy', metrics=['accuracy'])
いざ学習
nb_epoch
は回数。validation_split
は検証に使うデータの割合(全体のデータを学習に使わず、8割のみを学習に使って、残りの2割を評価に使う)。
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
sum(predict == real) / 200.0
おおよそ98%くらいの精度で判別できている。まあこんな簡単な条件だし。
ちなみに学習を回さずに判別させると50%くらいになる。まあ適当にやって当たる確率は50%なので。
今回のプログラムまとめ
モデルを定義するときに同時にレイヤーも積み重ねている。
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)