- 印刷する
- PDF
Keras image classification
- 印刷する
- PDF
Classic/VPC環境で利用できます。
このチュートリアルでは、スニーカーやシャツのような服の画像を分類するニューラルネットワークモデルの訓練を行います。詳細内容が全部理解できなくても構いません。ここでは、完全なTensorFlowプログラムをざっと見てみます。詳細内容はこれから学びながら説明していきます。
ここでは、TensorFlowモデルを作成して訓練することができる高レベルAPIのtf.kerasを使用します。
# tensorflowとtf.kerasをインポートします。
import tensorflow as tf
from tensorflow import keras
# ヘルパー(helper)ライブラリをインポートします。
import numpy as np
import matplotlib.pyplot as plt
print(tf.__version__)
ファッションMNISTデータセットをインポートする
10のカテゴリ(category)と70,000の白黒画像で構成されたファッションMNISTデータセットを使用します。画像の解像度(28x28ピクセル)は低く、以下のように個別の服の品目を表します。
ファッションMNISTは、コンピュータビジョン分野の「Hello, World」プログラムに相当する古典的なMNISTデータセットに代わってよく使われます。MNISTデータセットは手書き数字(0、1、2など)の画像でできています。ここで使用する服の画像と同じフォーマットです。
ファッションMNISTは一般的なMNISTより少々難しい問題で、様々な例を作るために選択しました。両データセットは比較的小さいため、アルゴリズムが作動しているかどうかを確認するためによく使われます。コードをテストしてデバッグする用途に適しています。
ネットワークを訓練するのに60,000の画像を使用します。その次は、ネットワークがどれくらい正確に画像を分類するのか、10,000の画像で評価します。ファッションMNISTデータセットは、TensorFlowで直接インポートしてロードすることができます。
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
load_data()関数を呼び出すと、4つのNumPy配列が返されます。
- train_imagesとtrain_labels配列はモデル学習に使用される訓練セットです。
- test_imagesとtest_labels配列はモデルテストに使用されるテストセットです。
画像は28x28サイズのNumPy配列で、ピクセル値は0と255の間です。ラベル(label)は0から9までの整数配列です。この値は、画像にある服のクラス(class)を表します。
ラベル | クラス |
---|---|
0 | T-shirt/top |
1 | Trouser |
2 | Pullover |
3 | Dress |
4 | Coat |
5 | Sandal |
6 | Shirt |
7 | Sneaker |
8 | Bag |
9 | Ankle boot |
各画像は1つのラベルにマッピングされています。データセットにクラス名が入っていないため、後に画像を出力する際に使用するための別途変数を作成して保存します。
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
データの探索
モデルを訓練する前に、データセットの構造を調べてみましょう。以下のコードは、訓練セットに60,000の画像があるということを示しています。各画像は28x28ピクセルで表現されます。
train_images.shape
# (60000, 28, 28)
同様に、訓練セットには60,000のラベルがあります。
len(train_labels)
# 60000
各ラベルは0と9の間の整数です。
train_labels
# array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)
テストセットには10,000の画像があります。この画像も28x28ピクセルで表現されます。
test_images.shape
# (10000, 28, 28)
テストセットは10,000の画像に対するラベルを持っています。
len(test_labels)
# 10000
データの前処理
ネットワークを訓練する前に、データを前処理する必要があります。訓練セットにある1番目の画像を見ると、ピクセル値の範囲が0~255の間であることがわかります。
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()
ニューラルネットワークモデルに注入する前に、この値を範囲を0~1に調整します。そうするには、255で割る必要があります。訓練セットとテストセットを同じ方式で前処理するのがポイントです。
train_images = train_images / 255.0
test_images = test_images / 255.0
訓練セットで最初の25の画像とその下のクラス名を出力してみましょう。データフォーマットが正しいか確認し、ネットワークの構成と訓練の準備を終えます。
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()
モデルの構成
ニューラルネットワークモデルを作成するには、モデルの層を構成してモデルをコンパイルします。
層の設定
ニューラルネットワークの基本構成要素は層(layer)です。層は、注入されたデータから表現を抽出します。おそらく問題の解決により役立つ表現が抽出されるでしょう。
ほとんどの深層学習は、簡単な層をつないで構成されます。tf.keras.layers.Denseのような層の加重値(parameter)は、訓練中に学習されます。
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(10, activation='softmax')
])
このネットワークの1番目の層であるtf.keras.layers.Flattenは、2次元配列(28 x 28ピクセル)の画像フォーマットを28*28=784ピクセルの1次元配列に変換します。この層は、画像にあるピクセルの行を展開して一列に伸ばします。この層には学習される加重値はなく、データの変換のみ行います。
ピクセルを展開した後は、2つのtf.keras.layers.Dense層が連続して結合されます。この層を密結合(densely-connected)または全結合(fully-connected)層と呼びます。1番目のDense層は、128のノード(またはニューロン)を持ちます。2番目(最後)の層は、10のノードのソフトマックス(softmax)層です。この層は10の確率を返します。返された値を全部足すと1になります。各ノードは、現在の画像が10のクラスのうち一つに属する確率を出力します。
モデルのコンパイル
モデルを訓練する前に必要ないくつかの設定が、モデルのコンパイル段階で追加されます。
- 損失関数(Loss function)-訓練中にモデルの誤差を測定します。モデルの学習が正しい方向に進むように、この関数を最小化する必要があります。
- オプティマイザー(Optimizer)-データと損失関数に基づいてモデルのアップデート方法を決めます。
- 指標(Metrics)-訓練段階とテスト段階をモニタリングするために使用します。以下の例では、正しく分類された画像の割合である精度を使用します。
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
モデルの訓練
ニューラルネットワークモデルを訓練する段階は、以下のとおりです。
- 訓練データをモデルに注入します。この例ではtrain_imagesとtrain_labels配列です。
- モデルが画像とラベルをマッピングする方法を学びます。
- テストセットに対するモデルの予測を作成します。この例ではtest_images配列です。この予測がtest_labels配列のラベルと合っているか確認します。
訓練を開始するためにmodel.fitメソッドを呼び出すと、モデルが訓練データを学習します。
model.fit(train_images, train_labels, epochs=5)
"""
Epoch 1/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.4985 - accuracy: 0.8238
Epoch 2/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3755 - accuracy: 0.8645
Epoch 3/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3355 - accuracy: 0.8769
Epoch 4/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.3130 - accuracy: 0.8852
Epoch 5/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.2945 - accuracy: 0.8907
<tensorflow.python.keras.callbacks.History at 0x7f5c9cc0f400>
"""
モデルが訓練され、損失と精度指標が出力されます。このモデルは、訓練セットで約0.88(88%)程度の精度を達成します。
精度の評価
次は、テストセットでモデルの性能を比べます。
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print('\nテスト精度:', test_acc)
"""
313/313 - 0s - loss: 0.3619 - accuracy: 0.8754
テスト精度:0.8754000067710876
"""
テストセットの精度は訓練セットの精度より少し低めです。訓練セットの精度とテストセットの精度の差は、過剰適合(overfitting)のせいで生じます。過剰適合とは、機械学習モデルが訓練データより新しいデータで性能が低下する現象のことをいいます。
予測を作成する
訓練されたモデルを使用して画像に対する予測を作成することができます。
predictions = model.predict(test_images)
ここでは、テストセットにある各画像のラベルを予測しました。1番目の予測を確認してみましょう。
predictions[0]
"""
array([1.7927578e-04, 9.7309680e-07, 2.0041271e-05, 1.7340941e-06,
5.4875236e-06, 7.3947711e-03, 2.7816868e-04, 1.0243144e-01,
1.9015789e-04, 8.8949794e-01], dtype=float32)
"""
この予測は、10の数字の配列で現れます。この値は、10の服の品目に対応するモデルの信頼度(confidence)を表します。最も高い信頼度を持つラベルを探してみましょう。
np.argmax(predictions[0])
# 9
モデルは、この画像がアンクルブーツ(class_name[9])だともっとも確信しています。この値で合っているかテストラベルを確認してみましょう。
test_labels[0]
# 9
10のクラスに対する予測をすべてグラフで表現してみます。
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array[i], true_label[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
0番目の要素の画像、予測、信頼度点数の配列を確認してみます。
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
plt.show()
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
plt.show()
いくつかの画像の予測を出力してみましょう。正しく予測されたラベルは青で、誤った予測がされたラベルは赤です。数字は予測ラベルの信頼度パーセント(百点満点)です。信頼度の点数が高い場合でも、誤った予測をすることがあります。
# 最初のX個のテスト画像と予測ラベル、実際のラベルを出力します。
# 正しい予測は青で、誤った予測は赤で表します。
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions, test_labels)
plt.show()
最後に、訓練されたモデルを使用して1つの画像に対する予測を作成します。
# テストセットで画像を1つ選択します。
img = test_images[0]
print(img.shape)
# (28, 28)
tf.kerasモデルは、サンプルの束ねまたはバッチ(batch)でまとめて予測を作成するのに最適化しています。1つの画像を使用する場合でも2次元配列にしなければなりません。
# 画像を1つだけ使用する場合でもバッチに追加します。
img = (np.expand_dims(img,0))
print(img.shape)
# (1, 28, 28)
ではこの画像の予測を作成します。
predictions_single = model.predict(img)
print(predictions_single)
"""
[[1.7927596e-04 9.7309771e-07 2.0041271e-05 1.7340958e-06 5.4875236e-06
7. 3947711e-03 2.7816897e-04 1.0243144e-01 1.9015789e-04 8.8949794e-01]]
"""
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
model.predict
は2次元NumPy配列を返すので、1番目の画像の予測を選択します。
np.argmax(predictions_single[0])
# 9
前と同様、モデルの予測はラベル9です。
# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.