はじめに
前回はTensorFlowのラッパーライブラリであるKerasについて、環境構築からサンプルコードの実行まで行いました。
今回は実際の学習データからどこまで精度の高い機械学習アプリケーションを構築できるか試してみます。
テーマはサル、チンパンジー、ゴリラの識別です。

正直人間でも難しいと思われるこの3種を見分けることが出来るんでしょうか。
とりあえずやってみます。
TensorFlow + Kerasでサルを分類できるのか試してみる(2) ~ 学習データを増やして精度を上げる
動作環境
- macOS High Sierra Version 10.13
- python 3.6.3
- pyenv 1.1.5
- anaconda 3-5.0.0
- Keras 2.0.8
- tensorflow 1.3.0
環境準備
まずは学習プログラムの配置ディレクトリを作成し、ローカル環境をAnacondaに切り替えます。
$ mkdir ml-monkey $ cd ml-monkey $ pyenv local anaconda3-5.0.0
あらかじめanaconda3-5で作成していた仮想環境をアクティベートします。
$ source ~/.pyenv/versions/anaconda3-5.0.0/bin/activate keras
環境構築の手順についてはこちらを参考にして下さい。
学習データを準備
今回は「サル(monkey)」、「チンパンジー(chimpanzee)」、「ゴリラ(gorilla)」を識別する3クラス分類問題なので、それぞれの画像ファイルを取得します。
Webから拾ってきてもいいのですが、大量に必要になると手間がかかるので、写真共有サービスのFlickrのAPIを使って集めました。
flickr APIを使った画像データの取得については以下の記事を参照して下さい。
300枚ずつ計900枚の画像データを準備しました。
実際取得した画像の中にはノイズも含まれているので、手作業でクリーニングを行います。
ノイズ分を想定してそれぞれ50枚ほど多めにダウンロードしておきました。
地味な作業ですが、学習データの質がモデルの精度に大きく関係してしまうので地道に頑張ります。
画像ファイルを機械学習用のフォーマットに変換
学習用データをPNG形式で集めましたが、そのままでは使いづらいため、機械学習しやすいようにファイルフォーマットを変換します。
先にPythonの画像処理ライブラリであるPillowをインストールします。
$ pip install pillow
機械学習用のフォーマットに変換するスクリプトの全文です。
import glob
import traceback
import numpy as np
import sys
from PIL import Image
photo_count = 300
# 画像データ
X = []
# ラベル
Y = []
def convert_image_to_npz(folder, label, count):
images = glob.glob('./image-data/' + folder + '/*.jpg')
for i, image in enumerate(images):
if i > count:
break
# 読み取りモードで読み取り
image = Image.open(image, 'r')
# RGBへ変換
image = image.convert("RGB")
dataset = np.asarray(image)
dataset = dataset / 256
X.append(dataset)
Y.append(label)
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit("Usage: %s convert-npz.py <keyword1> <keyword2>" % sys.argv[0])
try:
output_file = 'monkey-dataset-' + str(photo_count)
for i, key in enumerate(sys.argv[1:]):
print(key)
convert_image_to_npz(key, i, photo_count)
X = np.array(X, dtype=np.float32)
np.savez(output_file, x=X, y=Y)
except Exception as e:
traceback.print_exc()
実行する時は引数にキーワードを指定して実行します。
Pillowで画像ファイルを読み取り、RGB形式へ変換します。
# 読み取りモードで読み取り
image = Image.open(image, 'r')
# RGBへ変換
image = image.convert("RGB")
次にndarrayを生成し、データを正規化します。
RGBは0~255の値を取るためです。
dataset = np.asarray(image) dataset = dataset / 256
PythonではデータをNumpyで扱うのが一般的です。
NPY/NPZ形式はnumpyオブジェクトをファイルに保存するためのフォーマットで、特にNPZ形式的は複数のnumpyオブジェクトを保存することができるので便利です。
学習データとラベルをNPZ形式でファイルに出力します。
np.savez(output_file, x=X, y=Y)
次はNPZファイルを読み込んで学習させてみます。
画像データを学習させる
それでは実際に機械学習させてみます。
データセットから学習モデルを生成し、テストデータについて分類を行うスクリプトです。
import traceback
import numpy as np
from keras.layers import Dense
from keras.models import Sequential
from sklearn.model_selection import train_test_split
classes = 3
data_size = 75 * 75 * 3
def model_training(x, y):
model = Sequential()
# 隠れ層:64、入力層:データサイズ、活性化関数:Relu
model.add(Dense(units=64, activation='relu', input_dim=(data_size)))
# 出力層:分類するクラス数、活性化関数:Softmax
model.add(Dense(units=classes, activation='softmax'))
# モデルをコンパイル
model.compile(loss='sparse_categorical_crossentropy',
optimizer='sgd',
metrics=['accuracy'])
model.fit(x, y, epochs=60)
return model
def model_evaluation(model, x_test, y_test):
score = model.evaluate(x_test, y_test)
print(score)
print('Loss = ', score[0])
print('Accuracy = ', score[1])
if __name__ == '__main__':
try:
# データの読み込み
data_set = np.load('./monkey-dataset-300.npz')
X = data_set["x"]
Y = data_set["y"]
# 2次元に変換
X = np.reshape(X, (-1, data_size))
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, train_size=0.8)
model = model_training(X_train, Y_train)
model_evaluation(model, X_test, Y_test)
except Exception as e:
traceback.print_exc()
Kerasはかなり直感的にニューラルネットワークを構築できるように設計されています。
入力層→(隠れ層) * N→出力層の順に要素を追加していくイメージです。
まずはSequential()でモデルを作成し、add()で要素を追加していきます。
Dense()はニューラルネットワークの層を指定します。
最初に画像のデータサイズ分のニューロンを持つ入力層と、64個のニューロンを持つ隠れ層を作成しています。
活性化関数にはRelu関数を使います。
Relu関数は入力xがx<=0であれば0を、x>0であればxを返す活性化関数です。
活性化関数にはいくつか種類がありますが、一般的にReluかReluの派生系の関数が使われているそうです。
他の関数もいくつか試してみたいと思います。
出力層への活性化関数にはSoftmax関数を使います。
Softmax関数は0~1の範囲で値を算出してくれるという特徴を持ち、分類問題の出力層に向けた活性化関数としてよく使われる関数です。
model.compile(loss='sparse_categorical_crossentropy',
optimizer='sgd',
metrics=['accuracy'])
モデルのコンパイル時に損失関数としてsparse_categorical_crossentropyを指定しています。
sparse_categorical_crossentropyはスパースなマルチクラス分類交差エントロピー関数です。
損失関数とはどれだけ正解から外れているかを計算する関数で、この値を小さくする方向に学習が進んでいくので目的関数とも呼ばれます。
optimizerでは最適化手法を指定します。確率的勾配降下法であるSGDを使います。
評価関数(metrics)はモデルの性能を測るために使われます。オーソドックスに’accuracy’を使います。
この辺のパラメータは解決したい問題によって最適なパターンが決まってくると思うので、試行錯誤してみたいです。
実行結果
Using TensorFlow backend. /Users/yuichi/.pyenv/versions/anaconda3-5.0.0/envs/keras/lib/python3.6/site-packages/sklearn/model_selection/_split.py:2010: FutureWarning: From version 0.21, test_size will always complement train_size unless both are specified. FutureWarning) Epoch 1/60 . . . Epoch 56/60 721/721 [==============================] - 0s - loss: 0.1450 - acc: 0.9681 Epoch 57/60 721/721 [==============================] - 0s - loss: 0.1599 - acc: 0.9570 Epoch 58/60 721/721 [==============================] - 0s - loss: 0.1539 - acc: 0.9626 Epoch 59/60 721/721 [==============================] - 0s - loss: 0.2740 - acc: 0.9029 Epoch 60/60 721/721 [==============================] - 0s - loss: 0.1578 - acc: 0.9584 32/181 [====>.........................] - ETA: 0s[1.0974566719150016, 0.64640884241346497] Loss = 1.09745667192 Accuracy = 0.646408842413
正解率0.64は少し低いですね。
何度か実行してみましたが、大体0.58~0.66の間に収まりました。
まあなんのチューニングもせずにデータ突っ込んで回してみただけなのでこんなものかもしれませんが。。
色々工夫してどこまで精度が上がるのか試してみたいと思います。
TensorFlow + Kerasでサルを分類できるのか試してみる(2) ~ 学習データを増やして精度を上げる