コンテンツにスキップ

第5章 画像認識

1 データの読み込み

画像を読み込み、その画像がなんであるかを予測します。 まず、学習データを読み込みます。KerasにはCIFAR-10という画像データが含まれていますので、これを読み込んでみましょう。

ファイル deep2.ipynb に以下を記述します。

from keras.datasets import cifar10
(x_train, y_train),(x_test, y_test) = cifar10.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

学習データの数、形式は以下で確認できます。

x_train.shape

32×32の50,000枚の画像があることがわかります。最後の3は色の数です(24BIT)。 テスト画像は10,000枚あります。

x_test.shape

2 画像の表示

画像は以下で表示できます。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo"])

plt.imshow(x_train[1])

最初の20枚を表示してみます。

for i in range(20):
    plt.subplot(4, 5, i+1)
    plt.axis("off")
    plt.imshow(x_train[i])

画像の答えは以下で分かります。

y_train[:20]

これは数値で、名前をリストで指定するなら以下のようになっています(0番が飛行機、1番が自動車……)。

names = ["飛行機", "自動車", "鳥", "ネコ", "シカ", "イヌ", "カエル", "ウマ", "船", "トラック"]

画像と合わせてタイトルを出してみます。

names = ["飛行機", "自動車", "鳥", "ネコ", "シカ", "イヌ", "カエル", "ウマ", "船", "トラック"]

plt.figure(figsize=(12,10))
for i in range(20):
    plt.subplot(4, 5, i+1)
    plt.axis("off")
    plt.imshow(x_train[i])
    plt.title(names[y_train[i][0]])

3 モデルの構築と学習

手書き文字認識と同様のモデルを構築します。 前回との違いは、入力データの形式が 32×32×3 なのでそれを一次元にする必要があることです。そのために最初の層で Flatten という層を入れ、データを一次元に変換します。

その後は前回と同じです。最後に10個に分類します。

import keras
from keras import layers

model = keras.models.Sequential()

model.add(layers.Flatten(input_shape=(32, 32, 3)))
model.add(layers.Dense(128, activation="relu"))
model.add(layers.Dense(128, activation="relu"))
model.add(layers.Dense(10, activation="softmax"))

model.summary()

コンパイルし、fitで学習を行います。エポック回数は10回とし行ってみます。

model.compile(optimizer="adam",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])

history = model.fit(x_train, y_train, epochs=10,
                    validation_data=(x_test, y_test))

test_loss, test_acc =model.evaluate(x_test, y_test)
print(f"正解率:{test_acc:.2%}")

しかし、正解率は50%弱程度のはずです。

4 CNNモデル

画像認識を寄り正確に行うには、CNN (convolutional Neural Network=畳み込みニューラルネットワーク) を使用します。

CNNでは画像を二次元のまま、特徴を学習し、効率的に処理することができます、 CNNでよく使われる主要な層には以下の2つがあります。

畳み込み層 (Convolutional Layer):

画像から特徴を抽出する層です。小さなサイズのフィルタを使用して画像全体を少しずつスキャンし、局所的な特徴を検出します。フィルタは何パターンも用意しますので、複数パターンの画像ができあがります。

Kerasでは以下のように定義します。

layers.Conv2D(32, (3, 3), activation="relu")

これは3×3サイズのフィルタを32パターン使用します。元の画像サイズが32×32の場合、これに3×3のサイズ毎にフィルタを適用して一つの値にします。これを画像の全領域で行います。フィルタが32パターンあるので、画像も32パターンできあがります。

プーリング層 (Pooling Layer):

画像サイズを縮小し画像を単純化します。過学習を抑制する効果もあります。

Kerasでは以下のように定義します。

layers.MaxPooling2D((2, 2))

これは2×2 の範囲で最大値を抽出することで画像サイズを半分に縮小します。

5 CNNモデルの構築と学習

CNNモデルで畳み込み層とプーリング層を2回ずつ入れます。 その後は64個→32個→10個とニューロンを減らしていきます。

model = keras.models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation="relu", input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(64, (3, 3), activation="relu"))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(32, activation="relu"))
model.add(layers.Dense(10, activation="softmax"))

model.summary()

これをコンパイルし学習します。

model.compile(optimizer="adam",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])

history = model.fit(x_train, y_train, epochs=10,
                    validation_data=(x_test, y_test))

test_loss, test_acc =model.evaluate(x_test, y_test)
print(f"正解率:{test_acc:.2%}")

テストデータの正解率は70%程度まで向上します。

過学習対策

過学習の対策として、プーリング層の後にドロップアウト層を入れます。これはランダムにニューロンを切り捨てるものです。

model.add(layers.Dropout(0,2))

6 正解率のグラフ表示

正解率を学習回数毎にグラフで表示してみます。accuracyが訓練データの正解率、val_accuracyがテストデータの正解率です。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo"])

plt.title("正解率")
plt.xlabel("学習回数")
plt.plot(history.history["accuracy"])
plt.plot(history.history["val_accuracy"])
plt.legend(["訓練","テスト"])
plt.show()

誤差を学習回数毎にグラフで表示してみます。lossが訓練データの正解率、val_lossがテストデータの正解率です。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo"])

plt.title("誤差")
plt.xlabel("学習回数")
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.legend(["訓練","テスト"])
plt.show()

7 画像を読み込んで推論

実際に画像を読み込んで推論してみましょう。 PILというライブラリを使用し、画像を読み込みます。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# 画像をPILで読み込む
im = Image.open('cat.jpg')

# 画像を表示
plt.imshow(im)
plt.show()

# 画像をリサイズ (32x32)
im = im.resize((32, 32))

# NumPy配列に変換し、正規化
im = np.array(im) / 255.0

# モデルで推論を行う
r = model.predict(np.array([im]))

# 結果の表示
for i, acc in enumerate(r[0]):
    print(f"{names[i]} : {acc:0.2f}")

8 モデルの保存

学習には時間がかかるため、一度学習したモデルは保存が出来ます。

model.save_weights('cifar10.weights.h5')

そして、それを読み込んで使うことが可能です。

model.load_weights('cifar10.weights.h5')

# モデルで推論を行う
r = model.predict(np.array([im]))

# 結果の表示
for i, acc in enumerate(r[0]):
    print(f"{names[i]} : {acc:0.2f}")