無から始めるKeras 第1回

  • 37
    Like
  • 1
    Comment

無から始める 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もレイヤー(層)を表すのだが、なんとなく「つなぐもの」をイメージしたほうがわかりやすい気がした。

名称未設定.001.jpeg

コンパイル

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

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)