Keras で iris を分類

Theano・TensorFlow 用のディープラーニングライブラリ Keras を使って、階層型ニューラルネットによる iris の分類を試してみました。

ソースは http://github.com/fits/try_samples/tree/master/blog/20160531/

準備

今回は Docker コンテナで Keras を実行するため、Docker の公式イメージ python をベースに Keras をインストールした Docker イメージを用意します。

Docker イメージ作成

/vagrant/work/keras/Dockerfile
FROM python

RUN apt-get update && apt-get upgrade -y

RUN pip install --upgrade pip

RUN pip install keras
RUN pip install scikit-learn

RUN apt-get clean

sklearn の iris データセットを使うために scikit-learn もインストールしていますが、Keras を使うだけなら不要です。

また、Theano はデフォルトでインストールされるようですが、TensorFlow を使う場合は別途インストールする必要がありそうです。(今回は Theano を使います)

Dockerfile に対して docker build を実行して Docker イメージを作成します。

Docker ビルド
$ cd /vagrant/work/keras
$ docker build --no-cache -t sample/py-keras:0.1 .

(1) 学習

まずは、iris のデータセットを全て使って学習してみます。

ConvnetJS で iris を分類」 で実施したように、出力層の活性化関数はソフトマックス、損失関数(誤差関数)に交差エントロピーを使います。

sklearn の iris データセットのように、ラベルデータ (target の値) が数値 (0 ~ 2) の場合 ※ に交差エントロピーを実施するには compile の引数で loss = 'sparse_categorical_crossentropy' と指定すれば良さそうです。

※ iris.target の内容

    [0 0 0 0 0 0 0 ・・・
     0 0 0 0 0 0 0 ・・・
     1 1 1 1 1 1 1 ・・・
     2 2 2 2 2 2 2 ・・・
     2 2]

とりあえず、入力層 - 隠れ層 - 出力層 (隠れ層のニューロン数 8)というレイヤー構成を使い、学習処理(fit)はミニバッチサイズを 1 として 50 回繰り返すように指定しました。

/vagrant/work/iris_sample1.py
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from sklearn import datasets

# モデルの定義
model = Sequential()

# 隠れ層の定義
model.add(Dense(input_dim = 4, output_dim = 8))
# 隠れ層の活性化関数
model.add(Activation('relu'))

# 出力層の定義
model.add(Dense(output_dim = 3))
# 出力層の活性化関数
model.add(Activation('softmax'))

model.compile(loss = 'sparse_categorical_crossentropy', optimizer = 'sgd', metrics = ['accuracy'])

iris = datasets.load_iris()

# 学習
model.fit(iris.data, iris.target, nb_epoch = 50, batch_size = 1)

docker run で Keras 用の Docker コンテナを起動した後、コンテナ内で上記を実行します。

実行例
$ docker run --rm -it -v /vagrant/work:/work sample/py-keras:0.1 bash

# cd /work
# python iris_sample1.py

Using Theano backend.
Epoch 1/50
  1/150 [..............................] - ETA: 0s - loss: 3.4213 - acc: 0.0000e  2/150 [..............................] - ETA: 0s - loss: 2.2539 - acc: 0.0000e・・・
Epoch 49/50
150/150 [==============================] - 0s - loss: 0.1225 - acc: 0.9533
Epoch 50/50
150/150 [==============================] - 0s - loss: 0.1525 - acc: 0.9333

誤差(loss)と正解率(acc)が出力されました。

(2) 学習と評価

次は、iris データセットを学習用と評価用に分割して学習と評価をそれぞれ実行してみます。

データセットを直接シャッフルする代わりに、0 ~ 149 の数値をランダムに配置した配列を numpy の random.permutation で作成し、学習・評価用のデータ分割に利用しました。

/vagrant/work/iris_sample2.py
import sys

from keras.models import Sequential
from keras.layers.core import Dense, Activation
from sklearn import datasets
import numpy as np

# 学習・評価用のデータ分割率
trainEvalRate = 0.7

# 学習の繰り返し回数
epoch = int(sys.argv[1])

# 隠れ層のニューロン数
neuNum = int(sys.argv[2])
# 隠れ層の活性化関数
act = sys.argv[3]

optm = sys.argv[4]

model = Sequential()

model.add(Dense(input_dim = 4, output_dim = neuNum))
model.add(Activation(act))

model.add(Dense(output_dim = 3))
model.add(Activation('softmax'))

model.compile(
    loss = 'sparse_categorical_crossentropy', 
    optimizer = optm, 
    metrics = ['accuracy']
)

iris = datasets.load_iris()

data_size = len(iris.data)
train_size = int(data_size * trainEvalRate)

perm = np.random.permutation(data_size)

# 学習用データ
x_train = iris.data[ perm[0:train_size] ]
y_train = iris.target[ perm[0:train_size] ]

# 学習
model.fit(x_train, y_train, nb_epoch = epoch, batch_size = 1)

print('-----')

# 評価用データ
x_test = iris.data[ perm[train_size:] ]
y_test = iris.target[ perm[train_size:] ]

# 評価
res = model.evaluate(x_test, y_test, batch_size = 1)

print(res)
実行例
# python iris_sample2.py 50 6 sigmoid adam

Using Theano backend.
Epoch 1/50
105/105 [==============================] - 0s - loss: 1.0751 - acc: 0.3524
Epoch 2/50
105/105 [==============================] - 0s - loss: 1.0417 - acc: 0.3524
・・・
Epoch 49/50
105/105 [==============================] - 0s - loss: 0.3503 - acc: 0.9714
Epoch 50/50
105/105 [==============================] - 0s - loss: 0.3458 - acc: 0.9714
-----
45/45 [==============================] - 0s
[0.35189295262098313, 0.97777777777777775]