ディープラーニングを使用した画像分類
ディープラーニングを用いて画像の分類を行います。
今回は画像分類のチュートリアルとしてよく用いられる猫と犬の画像の分類を実践してみます。
ライブラリのインポート
Pythonにおけるディープラーニングのライブラリとしては以下が有名です。
- TensorFlow および Keras
- PyTorch
今回の例ではTensorFlowおよびKerasを使用します。
import os
import numpy as np
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
from PIL import Image
import tensorflow as tf
from tensorflow.keras import utils as np_utils
from tensorflow.keras.preprocessing import image_dataset_from_directory
from tensorflow.keras.layers import Input, Dense, Conv2D, Flatten, Dropout, MaxPooling2D
データの取得
使用するデータを取得します。
今回使用するデータはTensorFlowのチュートリアルでも用いられている猫と犬の分類済み画像になります。
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')
train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')
train_cats_dir = os.path.join(train_dir, 'cats') # 学習用の猫画像のディレクトリ
train_dogs_dir = os.path.join(train_dir, 'dogs') # 学習用の犬画像のディレクトリ
validation_cats_dir = os.path.join(validation_dir, 'cats') # 検証用の猫画像のディレクトリ
validation_dogs_dir = os.path.join(validation_dir, 'dogs') # 検証用の犬画像のディレクトリ
Downloading data from https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip
68608000/68606236 [==============================] - 1s 0us/step
68616192/68606236 [==============================] - 1s 0us/step
犬と猫の画像はそれぞれtrain
という学習用の画像セットとvalidation
という検証用の画像のセットに分類されています。
では、それぞれの画像の数を確認してみましょう。
num_cats_tr = len(os.listdir(train_cats_dir))
num_dogs_tr = len(os.listdir(train_dogs_dir))
num_cats_val = len(os.listdir(validation_cats_dir))
num_dogs_val = len(os.listdir(validation_dogs_dir))
total_train = num_cats_tr + num_dogs_tr
total_val = num_cats_val + num_dogs_val
print('total training cat images:', num_cats_tr)
print('total training dog images:', num_dogs_tr)
print('total validation cat images:', num_cats_val)
print('total validation dog images:', num_dogs_val)
print("--")
print("Total training images:", total_train)
print("Total validation images:", total_val)
total training cat images: 1000
total training dog images: 1000
total validation cat images: 500
total validation dog images: 500
--
Total training images: 2000
Total validation images: 1000
一旦ここで、この後に使用するネットワークの学習用の定数を設定しておきます。
BATCH_SIZE = 128
epochs = 10
IMG_SIZE = (160, 160)
IMG_SHAPE = IMG_SIZE + (3,)
データの準備
取得したデータを元にimage_dataset_from_directory
関数を使用してデータセットを作成します。
教師データ、検証データそれぞれで用意します。
また、学習後のモデルを評価するためにテストデータセットも用意します。
今回、テストデータセットは検証データセットの一部を使用します。
# 教師データ
train_dataset = image_dataset_from_directory(train_dir,
shuffle=True,
batch_size=BATCH_SIZE,
image_size=IMG_SIZE)
# 検証データ
validation_dataset = image_dataset_from_directory(validation_dir,
shuffle=True,
batch_size=BATCH_SIZE,
image_size=IMG_SIZE)
val_batches = tf.data.experimental.cardinality(validation_dataset)
# テストデータセット
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
Found 2000 files belonging to 2 classes.
Found 1000 files belonging to 2 classes.
試しに画像を表示してみます。
class_names = train_dataset.class_names
plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
モデルの作成
画像を分類するためのモデルを作成しましょう。
def sample_model():
# モデルの構成を定義します。
inputs = Input(shape=IMG_SHAPE)
x = tf.keras.layers.experimental.preprocessing.Rescaling(1./255, offset= -1)(inputs) # データを0-1の範囲に正規化
x = Conv2D(16, 3, padding='same', activation='relu')(x)
x = MaxPooling2D()(x)
x = Conv2D(32, 3, padding='same', activation='relu')(x)
x = MaxPooling2D()(x)
x = Conv2D(64, 3, padding='same', activation='relu')(x)
x = MaxPooling2D()(x)
x = Flatten()(x)
x = Dense(512, activation='relu')(x)
outputs = Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
# モデルのコンパイル
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
return model
# モデルを作成
model = sample_model()
# モデルの構造を確認します
model.summary()
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 160, 160, 3)] 0
_________________________________________________________________
rescaling (Rescaling) (None, 160, 160, 3) 0
_________________________________________________________________
conv2d (Conv2D) (None, 160, 160, 16) 448
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 80, 80, 16) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 80, 80, 32) 4640
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 40, 40, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 40, 40, 64) 18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 20, 20, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 25600) 0
_________________________________________________________________
dense (Dense) (None, 512) 13107712
_________________________________________________________________
dense_1 (Dense) (None, 1) 513
=================================================================
Total params: 13,131,809
Trainable params: 13,131,809
Non-trainable params: 0
_________________________________________________________________
モデルの学習
それでは作成したモデルを学習してみましょう。
history = model.fit(train_dataset,
epochs=epochs,
validation_data=validation_dataset)
Epoch 1/10
16/16 [==============================] - 38s 335ms/step - loss: 1.0439 - accuracy: 0.5030 - val_loss: 0.6913 - val_accuracy: 0.5023
Epoch 2/10
16/16 [==============================] - 5s 265ms/step - loss: 0.6854 - accuracy: 0.5725 - val_loss: 0.6683 - val_accuracy: 0.6170
Epoch 3/10
16/16 [==============================] - 5s 257ms/step - loss: 0.6680 - accuracy: 0.5955 - val_loss: 0.6479 - val_accuracy: 0.6330
Epoch 4/10
16/16 [==============================] - 5s 256ms/step - loss: 0.6248 - accuracy: 0.6640 - val_loss: 0.6236 - val_accuracy: 0.6720
Epoch 5/10
16/16 [==============================] - 5s 258ms/step - loss: 0.5696 - accuracy: 0.7125 - val_loss: 0.5892 - val_accuracy: 0.7099
Epoch 6/10
16/16 [==============================] - 5s 259ms/step - loss: 0.5009 - accuracy: 0.7555 - val_loss: 0.6136 - val_accuracy: 0.6537
Epoch 7/10
16/16 [==============================] - 5s 261ms/step - loss: 0.4441 - accuracy: 0.8045 - val_loss: 0.6165 - val_accuracy: 0.7053
Epoch 8/10
16/16 [==============================] - 5s 261ms/step - loss: 0.3926 - accuracy: 0.8205 - val_loss: 0.6289 - val_accuracy: 0.6984
Epoch 9/10
16/16 [==============================] - 5s 259ms/step - loss: 0.3158 - accuracy: 0.8625 - val_loss: 0.6914 - val_accuracy: 0.6732
Epoch 10/10
16/16 [==============================] - 5s 260ms/step - loss: 0.2574 - accuracy: 0.8920 - val_loss: 0.7377 - val_accuracy: 0.6881
学習結果を可視化してみましょう。
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
モデルの転移学習
先程のように何もない状態からニューラルネットワークのモデルを構築することは実際の業務ではあまりなく、基本的には公開されている既に構築済み/事前学習済みのモデルをベースとすることが多いです。
今回はMobileNetV2というモデルをImageNetというデータセットで事前学習済みのモデルをベースとし、転移学習しましょう。
# ベースモデルを用意
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
base_model.trainable = False
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_160_no_top.h5
9412608/9406464 [==============================] - 0s 0us/step
9420800/9406464 [==============================] - 0s 0us/step
画像データの準備
先程のモデルでは画像のデータに対して1~0の範囲で正規化を行いました。
使用するモデルによって、データの範囲が異なります。
使用するライブラリによっては前処理用のメソッドが用意されています。今回はその前処理用のメソッドを利用します。
# モデル用の画像前処理のレイヤーを用意。
preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
モデルの構築
def create_model():
# モデルの構成を定義します。
inputs = tf.keras.Input(shape=(160, 160, 3))
x = preprocess_input(inputs)
x = base_model(x, training=False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
# モデルのコンパイル
base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
return model
model = create_model()
model.summary()
Model: "model_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_3 (InputLayer) [(None, 160, 160, 3)] 0
_________________________________________________________________
tf.math.truediv (TFOpLambda) (None, 160, 160, 3) 0
_________________________________________________________________
tf.math.subtract (TFOpLambda (None, 160, 160, 3) 0
_________________________________________________________________
mobilenetv2_1.00_160 (Functi (None, 5, 5, 1280) 2257984
_________________________________________________________________
global_average_pooling2d (Gl (None, 1280) 0
_________________________________________________________________
dropout (Dropout) (None, 1280) 0
_________________________________________________________________
dense_2 (Dense) (None, 1) 1281
=================================================================
Total params: 2,259,265
Trainable params: 1,281
Non-trainable params: 2,257,984
_________________________________________________________________
/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/optimizer_v2.py:356: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
"The `lr` argument is deprecated, use `learning_rate` instead.")
ではこのモデルを転移学習してみましょう。
history = model.fit(train_dataset,
epochs=epochs,
validation_data=validation_dataset)
Epoch 1/10
/usr/local/lib/python3.7/dist-packages/keras/backend.py:4994: UserWarning: "`binary_crossentropy` received `from_logits=True`, but the `output` argument was produced by a sigmoid or softmax activation and thus does not represent logits. Was this intended?"
'"`binary_crossentropy` received `from_logits=True`, but the `output`'
16/16 [==============================] - 14s 528ms/step - loss: 0.7151 - accuracy: 0.5650 - val_loss: 0.6436 - val_accuracy: 0.6330
Epoch 2/10
16/16 [==============================] - 7s 369ms/step - loss: 0.6210 - accuracy: 0.6730 - val_loss: 0.5553 - val_accuracy: 0.7248
Epoch 3/10
16/16 [==============================] - 7s 372ms/step - loss: 0.5470 - accuracy: 0.7365 - val_loss: 0.4899 - val_accuracy: 0.7844
Epoch 4/10
16/16 [==============================] - 7s 369ms/step - loss: 0.4960 - accuracy: 0.7705 - val_loss: 0.4400 - val_accuracy: 0.8314
Epoch 5/10
16/16 [==============================] - 7s 374ms/step - loss: 0.4285 - accuracy: 0.8305 - val_loss: 0.3819 - val_accuracy: 0.8693
Epoch 6/10
16/16 [==============================] - 7s 373ms/step - loss: 0.3840 - accuracy: 0.8590 - val_loss: 0.3464 - val_accuracy: 0.8956
Epoch 7/10
16/16 [==============================] - 7s 376ms/step - loss: 0.3640 - accuracy: 0.8735 - val_loss: 0.3203 - val_accuracy: 0.9071
Epoch 8/10
16/16 [==============================] - 7s 381ms/step - loss: 0.3256 - accuracy: 0.8925 - val_loss: 0.2858 - val_accuracy: 0.9278
Epoch 9/10
16/16 [==============================] - 7s 373ms/step - loss: 0.3026 - accuracy: 0.9060 - val_loss: 0.2601 - val_accuracy: 0.9427
Epoch 10/10
16/16 [==============================] - 7s 374ms/step - loss: 0.2787 - accuracy: 0.9130 - val_loss: 0.2469 - val_accuracy: 0.9369
学習結果を表示してみます。
先程のモデルを1から構築した場合よりも精度が向上している事がわかります。
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
モデルの評価
テストデータセットを使用してモデルの性能を検証しましょう。
loss, accuracy = model.evaluate(test_dataset)
print('Test accuracy :', accuracy)
1/1 [==============================] - 1s 1s/step - loss: 0.2511 - accuracy: 0.9219
Test accuracy : 0.921875
image_batch, label_batch = test_dataset.as_numpy_iterator().next()
predictions = model.predict_on_batch(image_batch).flatten()
predictions = tf.nn.sigmoid(predictions)
predictions = tf.where(predictions < 0.5, 0, 1)
print('予測結果:\n', predictions.numpy())
print('正解のラベル:\n', label_batch)
# 試しに9枚表示
plt.figure(figsize=(10, 10))
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(image_batch[i].astype("uint8"))
plt.title(class_names[predictions[i]])
plt.axis("off")
予測結果:
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
正解のラベル:
[0 0 1 0 0 1 1 1 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0
0 0 1 0 0 1 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 1 0 0 1 1 1 0 1
1 0 1 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 0 0 1 0 1 0 1 0 1 0 0 1 1
0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0]
ディープラーニングを使用した画像分類の実例
ディープラーニングを用いて画像の分類を行います。
今回は画像分類のチュートリアルにて猫と犬の画像の分類を実践してみます。
ライブラリのインポート
Pythonにおけるディープラーニングのライブラリとしては以下が有名です。
- TensorFlow および Keras
- PyTorch
今回の例ではTensorFlowおよびKerasを使用してみましょう。
import os
import numpy as np
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
from PIL import Image
import tensorflow as tf
from tensorflow.keras import utils as np_utils
from tensorflow.keras.preprocessing import image_dataset_from_directory
from tensorflow.keras.layers import Input, Dense, Conv2D, Flatten, Dropout, MaxPooling2D
データの取得
使用するデータを取得します。
今回の例ではTensorFlowのチュートリアルでも使用されている犬と猫の分類済みのデータセットを使用します。
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')
train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')
train_cats_dir = os.path.join(train_dir, 'cats') # 学習用の猫画像のディレクトリ
train_dogs_dir = os.path.join(train_dir, 'dogs') # 学習用の犬画像のディレクトリ
validation_cats_dir = os.path.join(validation_dir, 'cats') # 検証用の猫画像のディレクトリ
validation_dogs_dir = os.path.join(validation_dir, 'dogs') # 検証用の犬画像のディレクトリ
Downloading data from https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip
68608000/68606236 [==============================] - 1s 0us/step
68616192/68606236 [==============================] - 1s 0us/step
犬と猫の画像はそれぞれtrain
という学習用の画像セットとvalidation
という検証用の画像のセットに分類されています。
では、それぞれの画像の数を確認してみましょう。
num_cats_tr = len(os.listdir(train_cats_dir))
num_dogs_tr = len(os.listdir(train_dogs_dir))
num_cats_val = len(os.listdir(validation_cats_dir))
num_dogs_val = len(os.listdir(validation_dogs_dir))
total_train = num_cats_tr + num_dogs_tr
total_val = num_cats_val + num_dogs_val
print('total training cat images:', num_cats_tr)
print('total training dog images:', num_dogs_tr)
print('total validation cat images:', num_cats_val)
print('total validation dog images:', num_dogs_val)
print("--")
print("Total training images:", total_train)
print("Total validation images:", total_val)
total training cat images: 1000
total training dog images: 1000
total validation cat images: 500
total validation dog images: 500
--
Total training images: 2000
Total validation images: 1000
一旦ここで、この後に使用するネットワークの学習用の定数を設定しておきます。
BATCH_SIZE = 128
epochs = 10
IMG_SIZE = (160, 160)
IMG_SHAPE = IMG_SIZE + (3,)
データの準備
画像データを準備します。
先程取得した画像データを元にimage_dataset_from_directory
という関数を使用してデータセットを作成します。
また、テスト用のデータセットを用意しましょう。
今回は検証用のデータセットの一部をテストデータセットとして利用します。
学習後にデータの性能を確認するためテスト用のデータセットを使用して推測を行います。
# 教師データ
train_dataset = image_dataset_from_directory(train_dir,
shuffle=True,
batch_size=BATCH_SIZE,
image_size=IMG_SIZE)
# 検証データ
validation_dataset = image_dataset_from_directory(validation_dir,
shuffle=True,
batch_size=BATCH_SIZE,
image_size=IMG_SIZE)
val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
# テストデータセット
validation_dataset = validation_dataset.skip(val_batches // 5)
Found 2000 files belonging to 2 classes.
Found 1000 files belonging to 2 classes.
試しに画像を表示してみます。
class_names = train_dataset.class_names
plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
モデルの作成
画像を分類するためのモデルを作成します。
今回は3層の畳み込み層を持つシンプルなモデルを作成します。
def sample_model():
# モデルの構成を定義します。
inputs = Input(shape=IMG_SHAPE)
x = tf.keras.layers.experimental.preprocessing.Rescaling(1./255, offset= -1)(inputs) # データを0-1の範囲に正規化
x = Conv2D(16, 3, padding='same', activation='relu')(x) # 1つ目の畳み込み層
x = MaxPooling2D()(x)
x = Conv2D(32, 3, padding='same', activation='relu')(x) # 2つ目の畳み込み層
x = MaxPooling2D()(x)
x = Conv2D(64, 3, padding='same', activation='relu')(x) # 3つ目の畳み込み層
x = MaxPooling2D()(x)
x = Flatten()(x)
x = Dense(512, activation='relu')(x)
outputs = Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
# モデルのコンパイル
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
return model
# モデルを作成
model = sample_model()
# モデルの構造を確認します
model.summary()
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 160, 160, 3)] 0
_________________________________________________________________
rescaling (Rescaling) (None, 160, 160, 3) 0
_________________________________________________________________
conv2d (Conv2D) (None, 160, 160, 16) 448
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 80, 80, 16) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 80, 80, 32) 4640
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 40, 40, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 40, 40, 64) 18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 20, 20, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 25600) 0
_________________________________________________________________
dense (Dense) (None, 512) 13107712
_________________________________________________________________
dense_1 (Dense) (None, 1) 513
=================================================================
Total params: 13,131,809
Trainable params: 13,131,809
Non-trainable params: 0
_________________________________________________________________
モデルの学習
それでは作成したモデルを学習してみましょう。
history = model.fit(train_dataset,
epochs=epochs,
validation_data=validation_dataset)
Epoch 1/10
16/16 [==============================] - 38s 335ms/step - loss: 1.0439 - accuracy: 0.5030 - val_loss: 0.6913 - val_accuracy: 0.5023
Epoch 2/10
16/16 [==============================] - 5s 265ms/step - loss: 0.6854 - accuracy: 0.5725 - val_loss: 0.6683 - val_accuracy: 0.6170
Epoch 3/10
16/16 [==============================] - 5s 257ms/step - loss: 0.6680 - accuracy: 0.5955 - val_loss: 0.6479 - val_accuracy: 0.6330
Epoch 4/10
16/16 [==============================] - 5s 256ms/step - loss: 0.6248 - accuracy: 0.6640 - val_loss: 0.6236 - val_accuracy: 0.6720
Epoch 5/10
16/16 [==============================] - 5s 258ms/step - loss: 0.5696 - accuracy: 0.7125 - val_loss: 0.5892 - val_accuracy: 0.7099
Epoch 6/10
16/16 [==============================] - 5s 259ms/step - loss: 0.5009 - accuracy: 0.7555 - val_loss: 0.6136 - val_accuracy: 0.6537
Epoch 7/10
16/16 [==============================] - 5s 261ms/step - loss: 0.4441 - accuracy: 0.8045 - val_loss: 0.6165 - val_accuracy: 0.7053
Epoch 8/10
16/16 [==============================] - 5s 261ms/step - loss: 0.3926 - accuracy: 0.8205 - val_loss: 0.6289 - val_accuracy: 0.6984
Epoch 9/10
16/16 [==============================] - 5s 259ms/step - loss: 0.3158 - accuracy: 0.8625 - val_loss: 0.6914 - val_accuracy: 0.6732
Epoch 10/10
16/16 [==============================] - 5s 260ms/step - loss: 0.2574 - accuracy: 0.8920 - val_loss: 0.7377 - val_accuracy: 0.6881
学習結果を可視化してみましょう。
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
モデルの転移学習
先程のように何もない状態からニューラルネットワークのモデルを構築することは実際の業務ではあまりなく、基本的には公開されている既に構築済み/事前学習済みのモデルをベースとすることが多いです。
今回はMobileNetV2というモデルをImageNetというデータセットで事前学習済みのモデルをベースとし、転移学習しましょう。
# ベースモデルを用意
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
base_model.trainable = False
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_160_no_top.h5
9412608/9406464 [==============================] - 0s 0us/step
9420800/9406464 [==============================] - 0s 0us/step
画像データの準備
先程のモデルでは画像のデータに対して1~0の範囲で正規化を行いました。
使用するモデルによって、データの範囲が異なります。
使用するライブラリによっては前処理用のメソッドが用意されています。今回はその前処理用のメソッドを利用します。
# モデル用の画像前処理のレイヤーを用意。
preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
モデルの構築
def create_model():
# モデルの構成を定義します。
inputs = tf.keras.Input(shape=(160, 160, 3))
x = preprocess_input(inputs)
x = base_model(x, training=False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
# モデルのコンパイル
base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
return model
model = create_model()
model.summary()
Model: "model_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_3 (InputLayer) [(None, 160, 160, 3)] 0
_________________________________________________________________
tf.math.truediv (TFOpLambda) (None, 160, 160, 3) 0
_________________________________________________________________
tf.math.subtract (TFOpLambda (None, 160, 160, 3) 0
_________________________________________________________________
mobilenetv2_1.00_160 (Functi (None, 5, 5, 1280) 2257984
_________________________________________________________________
global_average_pooling2d (Gl (None, 1280) 0
_________________________________________________________________
dropout (Dropout) (None, 1280) 0
_________________________________________________________________
dense_2 (Dense) (None, 1) 1281
=================================================================
Total params: 2,259,265
Trainable params: 1,281
Non-trainable params: 2,257,984
_________________________________________________________________
/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/optimizer_v2.py:356: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
"The `lr` argument is deprecated, use `learning_rate` instead.")
ではこのモデルを転移学習してみましょう。
history = model.fit(train_dataset,
epochs=epochs,
validation_data=validation_dataset)
Epoch 1/10
/usr/local/lib/python3.7/dist-packages/keras/backend.py:4994: UserWarning: "`binary_crossentropy` received `from_logits=True`, but the `output` argument was produced by a sigmoid or softmax activation and thus does not represent logits. Was this intended?"
'"`binary_crossentropy` received `from_logits=True`, but the `output`'
16/16 [==============================] - 14s 528ms/step - loss: 0.7151 - accuracy: 0.5650 - val_loss: 0.6436 - val_accuracy: 0.6330
Epoch 2/10
16/16 [==============================] - 7s 369ms/step - loss: 0.6210 - accuracy: 0.6730 - val_loss: 0.5553 - val_accuracy: 0.7248
Epoch 3/10
16/16 [==============================] - 7s 372ms/step - loss: 0.5470 - accuracy: 0.7365 - val_loss: 0.4899 - val_accuracy: 0.7844
Epoch 4/10
16/16 [==============================] - 7s 369ms/step - loss: 0.4960 - accuracy: 0.7705 - val_loss: 0.4400 - val_accuracy: 0.8314
Epoch 5/10
16/16 [==============================] - 7s 374ms/step - loss: 0.4285 - accuracy: 0.8305 - val_loss: 0.3819 - val_accuracy: 0.8693
Epoch 6/10
16/16 [==============================] - 7s 373ms/step - loss: 0.3840 - accuracy: 0.8590 - val_loss: 0.3464 - val_accuracy: 0.8956
Epoch 7/10
16/16 [==============================] - 7s 376ms/step - loss: 0.3640 - accuracy: 0.8735 - val_loss: 0.3203 - val_accuracy: 0.9071
Epoch 8/10
16/16 [==============================] - 7s 381ms/step - loss: 0.3256 - accuracy: 0.8925 - val_loss: 0.2858 - val_accuracy: 0.9278
Epoch 9/10
16/16 [==============================] - 7s 373ms/step - loss: 0.3026 - accuracy: 0.9060 - val_loss: 0.2601 - val_accuracy: 0.9427
Epoch 10/10
16/16 [==============================] - 7s 374ms/step - loss: 0.2787 - accuracy: 0.9130 - val_loss: 0.2469 - val_accuracy: 0.9369
学習結果を表示してみます。
先程のモデルを1から構築した場合よりも精度が向上している事がわかります。
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
モデルの評価
テストデータセットを使用してモデルの性能を検証しましょう。
loss, accuracy = model.evaluate(test_dataset)
print('Test accuracy :', accuracy)
1/1 [==============================] - 1s 1s/step - loss: 0.2511 - accuracy: 0.9219
Test accuracy : 0.921875
image_batch, label_batch = test_dataset.as_numpy_iterator().next()
predictions = model.predict_on_batch(image_batch).flatten()
predictions = tf.nn.sigmoid(predictions)
predictions = tf.where(predictions < 0.5, 0, 1)
print('予測結果:\n', predictions.numpy())
print('正解のラベル:\n', label_batch)
# 試しに9枚表示
plt.figure(figsize=(10, 10))
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(image_batch[i].astype("uint8"))
plt.title(class_names[predictions[i]])
plt.axis("off")
予測結果:
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
正解のラベル:
[0 0 1 0 0 1 1 1 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0
0 0 1 0 0 1 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 1 0 0 1 1 1 0 1
1 0 1 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 0 0 1 0 1 0 1 0 1 0 0 1 1
0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0]
参考資料
TensorFlow チュートリアル