この数年の間に深層ニューラル・ネットワークと深層学習がよく使われるようになってきました。それは、AlexNet、VGG、GoogleNet、ResNet で始まった研究で達成された飛躍的進歩のおかげです。2015 年、ResNet を使用した大規模な画像認識のパフォーマンスが精度の点で大幅に改善されたことが、深層ニューラル・ネットワークの人気が高まるきっかけとなったのです。
この記事では、基本的な深層ニューラル・ネットワークを使用して画像分類の問題を解決する方法を説明します。この記事で重視するのは、モデルを完全なものにすることよりも、全体的な手法とライブラリーの使用法です。結果を改善する方法については、パート 2 で説明します。
私が深層ニューラル・ネットワークを使用して解決したかったのは、画像認識の「hello world」バージョンのようなものではなく、例えば MNIST の手書き文字の認識といった問題です。TensorFlow と Keras のライブラリーに関する最初のチュートリアルに目を通した後、同じように見える一連の画像の中に含まれる所定の画像がチワワ (犬種) であるか、それともマフィンであるかを分類するという課題に取り掛かりました。
この記事に付属のデータ・セットは、このソースとインターネットでの検索結果を結合したものに、基本的な画像処理手法を適用して作成されています。データ・セットに含まれる画像は、Creative Commons の公正な使用に関するポリシーに従って収集、使用、提供しています。用途としては、(人工ニューラル・ネットワークを使用した画像認識の科学的研究の場合) TensorFlow および Keras ライブラリーを使用して処理するよう意図されています。このソリューションは https://www.tensorflow.org/tutorials/keras/basic_classification で使っている手法と同じ手法を適用しています。
基本的に、この記事を読む際の前提条件はありませんが、コードに従うとしたら、Python と numpy
の基礎知識があると役立ちます。また、TensorFlow および Keras ライブラリーをひと通り調べておくこともお勧めします。
データをインポートする
Git リポジトリーを複製する
$ git clone https://github.com/ScrapCodes/image-recognition-tensorflow.git
$ cd image-recognition-tensorflow
$ python
>>>
TensorFlow、Keras、その他のヘルパー・ライブラリーをインポートする
機械学習の実行には TensorFlow と Keras を使用し、画像処理には Pillow Python ライブラリーを使用しました。
macOS 上では、以下のように pip を使用してインストールできます。
sudo pip install tensorflow matplotlib pillow
注: sudo を使用する必要があるかどうかは、システム上に Python と pip がどのようにインストールされているかによって決まります。仮想環境を使用して構成されているシステムでは、sudo を使用する必要はありません。
Python ライブラリーをインポートします。
# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras
# Helper libraries
import numpy as np
import matplotlib.pyplot as plt
import glob, os
import re
# Pillow
import PIL
from PIL import Image
データをロードする
以下の Python 関数を使用して入力画像を前処理します。画像を numpy
配列に変換するには、すべての画像が同じサイズでなければなりません。
# Use Pillow library to convert an input jpeg to a 8 bit grey scale image array for processing.
def jpeg_to_8_bit_greyscale(path, maxsize):
img = Image.open(path).convert('L') # convert image to 8-bit grayscale
# Make aspect ratio as 1:1, by applying image crop.
# Please note, croping works for this data set, but in general one
# needs to locate the subject and then crop or scale accordingly.
WIDTH, HEIGHT = img.size
if WIDTH != HEIGHT:
m_min_d = min(WIDTH, HEIGHT)
img = img.crop((0, 0, m_min_d, m_min_d))
# Scale the image to the requested maxsize by Anti-alias sampling.
img.thumbnail(maxsize, PIL.Image.ANTIALIAS)
return np.asarray(img)
以下の Python 関数を使用して、画像のデータ・セットを numpy
配列にロードします。
def load_image_dataset(path_dir, maxsize):
images = []
labels = []
os.chdir(path_dir)
for file in glob.glob("*.jpg"):
img = jpeg_to_8_bit_greyscale(file, maxsize)
if re.match('chihuahua.*', file):
images.append(img)
labels.append(0)
elif re.match('muffin.*', file):
images.append(img)
labels.append(1)
return (np.asarray(images), np.asarray(labels))
実際の画像解像度よりも小さい、統一されたサイズに画像をスケーリングする必要があります。画像のサイズは 170×170 よりも大きいので、すべての画像を 100×100 に揃え、処理できる状態にします。
maxsize = 100, 100
データをロードするために、以下の関数を実行してトレーニング・データ・セットとテスト・データ・セットを読み込みます。
(train_images, train_labels) = load_image_dataset('/Users/yourself/image-recognition-tensorflow/chihuahua-muffin', maxsize)
(test_images, test_labels) = load_image_dataset('/Users/yourself/image-recognition-tensorflow/chihuahua-muffin/test_set', maxsize)
- train_images と train_lables はトレーニング・データ・セットです。
- test_images と test_labels は、未知のデータに対してモデルのパフォーマンスを検証するために使用するテスト・データ・セットです。
最後に、データ・セットで使用するクラス名を定義します。このデータには 2 つのクラスしかないので (画像はチワワまたはマフィンのいずれかです)、class_names
を次のように定義します。
class_names = ['chihuahua', 'muffin']
データを探索する
このデータ・セットには、チワワの画像とマフィンの加増を合わせて全部で 26 点のトレーニング・サンプルが含まれています。
train_images.shape
(26, 100, 100)
各画像に該当するラベル (0
または 1
) が付いています。0
は class_names[0]
(chihuahua
) を意味し、1
は class_names[1]
(muffin
) を意味します。
print(train_labels)
[0 0 0 0 1 1 1 1 1 0 1 0 0 1 1 0 0 1 1 0 1 1 0 1 0 0]
テスト・データ・セットとして、全部で 14 点 (クラスごとに 7 点) のサンプルがあります。
test_images.shape
(14, 100, 100)
print(test_labels)
[0 0 0 0 0 0 0 1 1 1 1 1 1 1]
データ・セットを視覚化する
matplotlib.pyplot
Python ライブラリーを使用してデータを視覚化できます。matplotlib ライブラリーがインストール済みであることを確認してください。
以下の Python ヘルパー関数を使用して、画像を画面上に描画できます。
def display_images(images, labels):
plt.figure(figsize=(10,10))
grid_size = min(25, len(images))
for i in range(grid_size):
plt.subplot(5, 5, i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[labels[i]])
トレーニング・データ・セットを視覚化しましょう。それには、以下のコードを使用します。
display_images(train_images, train_labels)
plt.show()
注: ロード時の画面は、前処理のステップでグレースケールに変換され、トリミングされています。
同じようにして、テスト・データ・セットも視覚化できます。トレーニング・データ・セットとテスト・データ・セットはどちらもかなり数が少ないので、遠慮なく、Google 検索で他のサンプルを探して追加し、動作やパフォーマンスの向上を確認してください。
データを前処理する
画像を 0 から 1 までの範囲の値にスケーリングする
train_images = train_images / 255.0
test_images = test_images / 255.0
モデルを作成する
レイヤーをセットアップする
合計で 4 つのレイヤーを使用します。最初のレイヤーでは、データ・セットを単一の配列にフラット化するだけで、トレーニングは行いません。他の 3 つのレイヤーは全結合レイヤーで、アクティベーション関数として sigmoid を使用します。
# Setting up the layers.
model = keras.Sequential([
keras.layers.Flatten(input_shape=(100, 100)),
keras.layers.Dense(128, activation=tf.nn.sigmoid),
keras.layers.Dense(16, activation=tf.nn.sigmoid),
keras.layers.Dense(2, activation=tf.nn.softmax)
])
モデルをコンパイルする
使用した最適化ツールは、確率的勾配降下 (SGD) です。
sgd = keras.optimizers.SGD(lr=0.01, decay=1e-5, momentum=0.7, nesterov=True)
model.compile(optimizer=sgd,
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
モデルをトレーニングする
model.fit(train_images, train_labels, epochs=100)
3 回のトレーニング・イテレーションが出力されます。
....
Epoch 98/100
26/26 [==============================] - 0s 555us/step - loss: 0.3859 - acc: 0.9231
Epoch 99/100
26/26 [==============================] - 0s 646us/step - loss: 0.3834 - acc: 0.9231
Epoch 100/100
26/26 [==============================] - 0s 562us/step - loss: 0.3809 - acc: 0.9231
<tensorflow.python.keras.callbacks.History object at 0x11e6c9590>
精度を評価する
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('Test accuracy:', test_acc)
14/14 [==============================] - 0s 8ms/step
('Test accuracy:', 0.7142857313156128)
テストの精度はトレーニングの精度よりも低くなっています。これは、モデルがデータを過学習していることを意味します。この問題を克服する手法については、パート 2 で説明します。このモデルは API を使用する好例ですが、完璧とは程遠い状態です。
最近の進化した画像認識手法と、さらに多くのトレーニング・データを使用すれば、問題に対するこのデータ・セットのパフォーマンスを大幅に向上させることができます。
予測を行う
予測を行うには、生成されたモデルに対して predict を呼び出せばよいだけです。
predictions = model.predict(test_images)
print(predictions)
[[0.6080283 0.3919717 ]
[0.5492342 0.4507658 ]
[0.54102856 0.45897144]
[0.6743213 0.3256787 ]
[0.6058993 0.39410067]
[0.472356 0.5276439 ]
[0.7122982 0.28770176]
[0.5260602 0.4739398 ]
[0.6514299 0.3485701 ]
[0.47610506 0.5238949 ]
[0.5501717 0.4498284 ]
[0.41266635 0.5873336 ]
[0.18961382 0.8103862 ]
[0.35493374 0.64506626]]
最後に画像を表示して、テスト・データ・セットに対するモデルのパフォーマンスを確認します。
display_images(test_images, np.argmax(predictions, axis = 1))
plt.show()
まとめ
この記事での結果では、上の画像で示しているように分類の誤りがいくつかあります。これでは完璧なモデルとは言えません。パート 2 で、トレーニングを改良する方法を説明します。