アプリ開発

「このブログはAidemy Premiumのカリキュラムの一環で、受講修了条件を満たすために公開しています。」

動作環境
・Google Colab
機械学習の手法
・CNN(vgg16転移学習)


テーマ:epoch数の調整とDropoutの有効性確認

0.乱数シードの固定

再現性の確保として以下のコードにて乱数を固定しています

random.seed(0)
tensorflow.random.set_seed(0)
np.random.seed(0)

1.元となるコード-cifar10を用いた飛行機と鳥の2クラス分類-

 #from  IPython.core.debugger import Pdb; Pdb().set_trace()
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Dense, Dropout, Flatten, Input
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras import optimizers
from tensorflow.keras.datasets import cifar10

# ----乱数固定------------------------------------------------------------------
import random
import tensorflow
random.seed(0)
tensorflow.random.set_seed(0)
np.random.seed(0)
# ----乱数固定------------------------------------------------------------------

# ----画像整理------------------------------------------------------------------
# cifar10読込
(X_train,y_train),(X_test,y_test) = cifar10.load_data()

# 256色(0~255)画像データの範囲を0~1に換算
X_train, X_test = X_train / 255., X_test / 255.

# 学習・検証に使う枚数を指定
train_num = 1000
test_num = 200

# 画像判定する枚数を指定
chk_num = 5
 #cifar10から飛行機 (インデックス:0)と鳥(インデックス:2)を取り出し、1000枚を学習、200枚を検証に使う
train_ind = np.where((y_train == 0) | (y_train == 2))[0]
train_ind = train_ind[:train_num]
X_train, y_train = X_train[train_ind], y_train[train_ind]

test_ind = np.where((y_test == 0) | (y_test == 2))[0]
chk_ind = test_ind[:test_num+chk_num]#test_indを更新する前に画像判定用の処理を行う
test_ind = test_ind[:test_num]
X_chk, y_chk = X_test[chk_ind], y_test[chk_ind]#X_test, y_testを更新する前に画像判定用の処理を行う
X_test, y_test = X_test[test_ind], y_test[test_ind]

# 1-hotベクトル化
y_train = to_categorical(y_train)[:,[0,2]]
y_test = to_categorical(y_test)[:,[0,2]]
y_chk = to_categorical(y_chk)[:,[0,2]]
# ----画像整理------------------------------------------------------------------

# ----モデル作成----------------------------------------------------------------
# vgg16のインスタンスの生成(画像サイズ32*32,カラー画像)
input_tensor = Input(shape=(32, 32, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

# モデル
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dense(2, activation='softmax'))

# モデルの連結
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

# vgg16の重みの固定
for layer in model.layers[:19]:
    layer.trainable = False

# 損失関数には交差エントロピーを採用
model.compile(loss='categorical_crossentropy',optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),metrics=['accuracy'])

# 学習実施
history = model.fit(X_train, y_train, batch_size=100, epochs=100, verbose=0, validation_data=(X_test, y_test))
 #acc , val_accのプロット
plt.plot(history.history["accuracy"], label="acc", ls="-", marker="o")
plt.plot(history.history["val_accuracy"], label="val_acc", ls="-", marker="x")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()
 #loss , val_lossのプロット
plt.plot(history.history["loss"], label="loss", ls="-", marker="o")
plt.plot(history.history["val_loss"], label="val_loss", ls="-", marker="x")
plt.ylabel("loss")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()

# 精度の評価
scores = model.evaluate(X_test, y_test, verbose=1)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])
# ----モデル作成----------------------------------------------------------------

# ----画像判定------------------------------------------------------------------
# 画像を一枚受け取り、飛行機か鳥かを判定して返す関数
def pred_cifar(img):

    # 念のため32*32以外の画像にも対応させる
    img = cv2.resize(img,(32,32))

    # 判定実施
    pred = np.argmax(model.predict(img.reshape(1,32,32,3)))

    if pred == 0:
        ans = "airplane"
    else:
        ans = "bird"
    return ans

# 検証データの次の画像を、渡す画像の1枚目のインデックスにする
index = test_num

for i in range(chk_num):
    # 判定する画像の表示
    img = X_chk[index+i]
    plt.imshow(img)
    plt.show()
    # 正解ラベルの表示
    if np.all(y_chk[index+i] == [1., 0.]):
        print("画像の種類:airplane")
    else:
        print("画像の種類:bird")
    # pred_cifar関数に画像を渡して判定
    print(pred_cifar(img))
# ----画像判定------------------------------------------------------------------

実行結果


7/7 [==============================] - 0s 10ms/step - loss: 0.4586 - accuracy: 0.8000
Test loss: 0.45864754915237427
Test accuracy: 0.800000011920929

画像の種類:airplane
1/1 [==============================] - 1s 526ms/step
bird

画像の種類:bird
1/1 [==============================] - 0s 30ms/step
bird

画像の種類:airplane
1/1 [==============================] - 0s 25ms/step
airplane

画像の種類:airplane
1/1 [==============================] - 0s 22ms/step
bird

画像の種類:airplane
1/1 [==============================] - 0s 19ms/step
airplane


2.Dropoutの導入

Dropout層のコードは以下となります

top_model.add(Dropout(rate =0.5))

導入したコードは以下となります

 #from  IPython.core.debugger import Pdb; Pdb().set_trace()
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Dense, Dropout, Flatten, Input
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras import optimizers
from tensorflow.keras.datasets import cifar10

# ----乱数固定------------------------------------------------------------------
import random
import tensorflow
random.seed(0)
tensorflow.random.set_seed(0)
np.random.seed(0)
# ----乱数固定------------------------------------------------------------------

# ----画像整理------------------------------------------------------------------
# cifar10読込
(X_train,y_train),(X_test,y_test) = cifar10.load_data()

# 256色(0~255)画像データの範囲を0~1に換算
X_train, X_test = X_train / 255., X_test / 255.

# 学習・検証に使う枚数を指定
train_num = 1000
test_num = 200

# 画像判定する枚数を指定
chk_num = 5
 #cifar10から飛行機 (インデックス:0)と鳥(インデックス:2)を取り出し、1000枚を学習、200枚を検証に使う
train_ind = np.where((y_train == 0) | (y_train == 2))[0]
train_ind = train_ind[:train_num]
X_train, y_train = X_train[train_ind], y_train[train_ind]

test_ind = np.where((y_test == 0) | (y_test == 2))[0]
chk_ind = test_ind[:test_num+chk_num]#test_indを更新する前に画像判定用の処理を行う
test_ind = test_ind[:test_num]
X_chk, y_chk = X_test[chk_ind], y_test[chk_ind]#X_test, y_testを更新する前に画像判定用の処理を行う
X_test, y_test = X_test[test_ind], y_test[test_ind]

# 1-hotベクトル化
y_train = to_categorical(y_train)[:,[0,2]]
y_test = to_categorical(y_test)[:,[0,2]]
y_chk = to_categorical(y_chk)[:,[0,2]]
# ----画像整理------------------------------------------------------------------

# ----モデル作成----------------------------------------------------------------
# vgg16のインスタンスの生成(画像サイズ32*32,カラー画像)
input_tensor = Input(shape=(32, 32, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

# モデル
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(rate =0.5))
top_model.add(Dense(2, activation='softmax'))

# モデルの連結
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

# vgg16の重みの固定
for layer in model.layers[:19]:
    layer.trainable = False

# 損失関数には交差エントロピーを採用
model.compile(loss='categorical_crossentropy',optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),metrics=['accuracy'])

# 学習実施
history = model.fit(X_train, y_train, batch_size=100, epochs=100, verbose=0, validation_data=(X_test, y_test))
 #acc , val_accのプロット
plt.plot(history.history["accuracy"], label="acc", ls="-", marker="o")
plt.plot(history.history["val_accuracy"], label="val_acc", ls="-", marker="x")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()
 #loss , val_lossのプロット
plt.plot(history.history["loss"], label="loss", ls="-", marker="o")
plt.plot(history.history["val_loss"], label="val_loss", ls="-", marker="x")
plt.ylabel("loss")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()

# 精度の評価
scores = model.evaluate(X_test, y_test, verbose=1)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])
# ----モデル作成----------------------------------------------------------------

# ----画像判定------------------------------------------------------------------
# 画像を一枚受け取り、飛行機か鳥かを判定して返す関数
def pred_cifar(img):

    # 念のため32*32以外の画像にも対応させる
    img = cv2.resize(img,(32,32))

    # 判定実施
    pred = np.argmax(model.predict(img.reshape(1,32,32,3)))

    if pred == 0:
        ans = "airplane"
    else:
        ans = "bird"
    return ans

# 検証データの次の画像を、渡す画像の1枚目のインデックスにする
index = test_num

for i in range(chk_num):
    # 判定する画像の表示
    img = X_chk[index+i]
    plt.imshow(img)
    plt.show()
    # 正解ラベルの表示
    if np.all(y_chk[index+i] == [1., 0.]):
        print("画像の種類:airplane")
    else:
        print("画像の種類:bird")
    # pred_cifar関数に画像を渡して判定
    print(pred_cifar(img))
# ----画像判定------------------------------------------------------------------

実行結果


7/7 [==============================] - 0s 15ms/step - loss: 0.4719 - accuracy: 0.7900
Test loss: 0.471892386674881
Test accuracy: 0.7900000214576721

画像の種類:airplane
1/1 [==============================] - 0s 144ms/step
bird

画像の種類:bird
1/1 [==============================] - 0s 19ms/step
bird

画像の種類:airplane
1/1 [==============================] - 0s 18ms/step
airplane

画像の種類:airplane
1/1 [==============================] - 0s 21ms/step
bird

画像の種類:airplane
1/1 [==============================] - 0s 19ms/step
airplane



Dropout導入前 Test loss: 0.45864754915237427
        Test accuracy: 0.800000011920929

Dropout導入後 Test loss: 0.471892386674881
        Test accuracy: 0.7900000214576721

epoch数100の場合、Dropoutを導入するとかえって性能が悪化してしまいました。
epoch数を変更することでDropoutに有効性が見られるか調査を行います。

3.epoch数の調整とDropoutの有効性確認

作成中

結論

作成中


この記事が気に入ったらサポートをしてみませんか?