TensorFlowをバックグラウンドで動作させるKerasを使って、scikit-learnで提供されているアヤメのデータセットを学習し、分類させる多層パーセプトロンのニューラルネットワークモデルを作ってみたので、サンプルコードを紹介する。
コンテンツ
TensorFlow環境の構築
今回はJupyterNotebookでコードを書いていく。
Anaconda仮想環境にTensorFlow環境を構築する必要があるので、下記の記事を参考にまずは環境構築をおこなう。
なお、ここで新しく構築した環境には後で登場する「Keras」や「scikit-learn」などのライブラリがインストールされていないため「pip install」コマンドで随時インストールをおこなう必要がある。
環境が用意できたらJupyterNotebookを起動し、以下のコードを実行する。
エラーが発生しなければOK。
※Using TensorFlow backend. のメッセージはエラーではない。
import tensorflow as tf
import keras
補足で説明しておくと「Keras」はTensorFlowのようなディープラーニングに対応したライブラリを、より簡単に扱うためのライブラリだ。
ただし「Keras」だけでは動作しないので、必ずTensorFlowなどのライブラリも同時に必要となる。
データセットの読み込み
今回使用するデータセットは「scikit-learn」から読み込む。
from sklearn import datasets
iris = datasets.load_iris()
x = iris.data
y = iris.target
また、読み込んだデータセットを説明変数(x)と目的変数(y)に分けておく。
それぞれのデータの中身を確認しよう。
x[:5]
# がくの長さ、がくの幅、花弁の長さ、花弁の幅
# array([[5.1, 3.5, 1.4, 0.2],
# [4.9, 3. , 1.4, 0.2],
# [4.7, 3.2, 1.3, 0.2],
# [4.6, 3.1, 1.5, 0.2],
# [5. , 3.6, 1.4, 0.2]])
y
# 0: Setosa, 1: Versicolor, 2: Virginica
xにはアヤメの特徴量が格納されており、それぞれの説明変数によってアヤメは3つの種類(y)に分類される。
このデータセットをディープラーニングさせたモデルを作り、アヤメの分類器を作っていく。
説明変数xの正規化
xは大体0.1〜8.0の間にデータが散らばっている。
データの正規化は、例えば身長・体重など単位の違う複数の説明変数を使用する際によく行われ、正規化をすることでモデルの精度が向上する場合がある。
今回xに対し、次のとおりscale関数を使って正規化をおこなう。
from sklearn import preprocessing
x = preprocessing.scale(x)
x[:5]
# array([[-0.90068117, 1.01900435, -1.34022653, -1.3154443 ],
# [-1.14301691, -0.13197948, -1.34022653, -1.3154443 ],
# [-1.38535265, 0.32841405, -1.39706395, -1.3154443 ],
# [-1.50652052, 0.09821729, -1.2833891 , -1.3154443 ],
# [-1.02184904, 1.24920112, -1.34022653, -1.3154443 ]])
これにより説明変数が平均値0、標準偏差1の値に正規化された。
目的変数yをダミー変数(One-Hot)に変換する
今回の目的変数は0、1、2のいずれかの値だが、これはアヤメの品種を表す値のため、量的データでなく質的データと言える。
この目的変数をそのまま使用すると、量的データとして認識され、結果として1.5や0.8などの半端な値が予測されてしまうことになる。
この問題を避けるため、目的変数を「One-Hot」と呼ばれる形式に変換する。
変換後のデータは次のとおり、行列形式にエンコーディングされる。
品種 | 変換前 | One-Hot |
Setosa | 0 | [1, 0, 0] |
Versicolor | 1 | [0, 1, 0] |
Virginica | 2 | [0, 0, 1] |
One-Hotへのエンコーディングは次のとおり、np_utilsを使えば良い。
from keras.utils import np_utils
y = np_utils.to_categorical(y)
# array([[1., 0., 0.],
# [1., 0., 0.],
# [1., 0., 0.],
# [1., 0., 0.],
# ...
説明変数を訓練データとテストデータに分割する
次に正規化した説明変数を、訓練データとテストデータに分割する。
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0)
モデルの作成と学習
Kerasを使ったモデルの学習の流れは、まずモデルを用意し、モデルにいくつかのパラメータを与えてcompileする。
そして最後にfit関数で訓練データを使って学習といった手順でおこなっていく。
まずはモデルの作成からパラメータを与えるところまで一気に見ていこう。
from keras.models import Sequential
from keras.layers.core import Dense, Activation
model = Sequential()
# Denseの第一引数は隠れ層のニューロン数を、
# 第二引数は入力層(がくの長さ、幅、花弁の長さ、幅)をタプル形式で指定
model.add(Dense(16, input_shape=(4,)))
model.add(Activation('relu'))
# 3種の分類をしたいので出力層は3を指定
model.add(Dense(3))
model.add(Activation('softmax'))
補足として、今回はニューロン数を16としたが特に決まりはなく、本来は学習の結果を見ながら調整するところだ。
また、Activationは活性化関数と呼ばれるものだが、ここでは深く掘り下げない。
さて、次はモデルをcompileし、fit関数で学習をおこなっていく。
model.compile(optimizer='adam', loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=50, batch_size=1, verbose=1)
補足すると、まずcompile関数のoptimizerで最適化アルゴリズムを指定する。
多数のアルゴリズムが用意されているが今回は「adam」を使用した。
次にlossだが、ここでは任意の損失関数を指定できる。
今回は「categorical_crossentropy」という関数を選択。
最後にmetricsだが、これは評価関数を意味し「accuracy」を選択した。
さて、いよいよモデルの学習をfit関数で実行するが、引数について簡単に紹介しておこう。
epochsは整数でモデルを訓練するエポック数(x・y全データの反復)を指定する。
batch_sizeは設定したサンプル数ごとに勾配の更新を行う。
verboseはログの表示形式を表す。
0はログを出力せず、1はプログレスバーで標準出力、2はエポックごとに1行のログを出力する。
今回はverboseに1を指定したので、fit関数を実行すると以下のように学習の過程が出力されるはずだ。
Epoch 1/50
112/112 [==============================] - 0s 2ms/step - loss: 1.3313 - accuracy: 0.3661
Epoch 2/50
112/112 [==============================] - 0s 784us/step - loss: 0.8698 - accuracy: 0.4554
Epoch 3/50
112/112 [==============================] - 0s 701us/step - loss: 0.7584 - accuracy: 0.7054
...
...
Epoch 48/50
112/112 [==============================] - 0s 708us/step - loss: 0.1079 - accuracy: 0.9732
Epoch 49/50
112/112 [==============================] - 0s 713us/step - loss: 0.1057 - accuracy: 0.9732
Epoch 50/50
112/112 [==============================] - 0s 728us/step - loss: 0.1042 - accuracy: 0.9732
ログの「loss」に注目してほしい。
この値が小さければ小さいほど、モデルの精度は高まっているということだ。
今回はepochsに50を指定したが、学習が進むにつれてloss値が小さくなっていることが分かる。
モデルの精度を評価
では学習したモデルの精度を測ってみよう。
loss, accuracy = model.evaluate(x_test, y_test, verbose=0)
print('Accuracy', '{:.2f}'.format(accuracy))
# Accuracy 0.97
97%とかなり高い精度の学習モデルができあがった。
実際にテストデータを使って分類をおこなってみる。
下記のとおり、分類の正解は「2([0, 0, 1])」のVirginicaだ。
print(x_test[:1])
print(y_test[:1])
# [[5.8 2.8 5.1 2.4]]
# [[0. 0. 1.]]
この説明変数を学習器に与えてみる。
model.predict_classes(x_test[:1], batch_size=1)
# array([2])
見事に正解結果が得られた。