質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

ResNet50を用いた転移学習における学習を正しく行いたい。

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 216

前提・実現したいこと

Google Coloboratory上で顔コレデータセットに対して4クラス分類を行っています。
Google Drive上のデータセットをImageDataGeneratorなどを用いて取り込み、学習をしようとしています。

発生している問題・エラーメッセージ

訓練データに対する学習はうまくいっているように思えるのですが、evaluate_generatorで評価した際のlossとグラフから見るlossのグラフの値が明らかに異なるという問題に直面しました。
どのような原因が考えられるでしょうか。また、そのためにはどのような操作が有効でしょうか?

イメージ説明 

closed accuracy: 0.4878048896789551
open accuracy: 0.47438329458236694

イメージ説明

closed loss: 2.028860092163086
open loss: 0.26708337664604187

該当のソースコード

python source code

#データ読み込み部↓↓
from keras.preprocessing.image import ImageDataGenerator
from keras.applications.resnet50 import preprocess_input, decode_predictions
from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
batch_size = 32
train_datagen = ImageDataGenerator(rotation_range=20,preprocessing_function=preprocess_input, rescale=1.0 / 255)
test_datagen = ImageDataGenerator(rescale=1.0 / 255,preprocessing_function=preprocess_input,)


train_generator = train_datagen.flow_from_directory(
    '#自分のドライブのフォルダパス', # kaokore
    target_size=(224, 224),
    batch_size=batch_size,
    class_mode='categorical')

test_generator = test_datagen.flow_from_directory(
    '#自分のドライブのフォルダパス',
    target_size=(224, 224),
    batch_size=1,
    class_mode='categorical')

#モデルの作成部
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense,Conv2D
from keras.preprocessing.image import ImageDataGenerator
from keras.applications.vgg16 import VGG16
from keras.applications.resnet50 import ResNet50

num_output_channels=32
size_kernel=(2,2)
batch_size = 32
epochs = 15
num_classes = 4

#base_model = VGG16(weights='imagenet')

#ResNet50の定義
base_model=ResNet50(weights='imagenet',include_top=False,input_shape=(224,224,3))

#上記の層に自作の層を追加
model = Sequential([base_model,
                    Conv2D(num_output_channels, kernel_size = size_kernel,padding='same',activation='relu' ,input_shape=(7,7,2048)),
                    MaxPooling2D(pool_size=(2,2)),
                    Flatten(),
                    Dense(num_classes),
                    Activation('softmax')])

#ResNet50のパラメータのスイッチ用
#base_model.trainable = True
base_model.trainable = False

#確認用
#base_model.summary()
#model.summary()

#modelのコンパイル
model.compile(loss='categorical_crossentropy',
               optimizer='adam',
               metrics=['accuracy'])

#学習フェーズ
%time history = model.fit_generator(train_generator, epochs=epochs,validation_data=test_generator)

#modelのセーブ&ロード
with open('model.json', 'w') as f:
    f.write(model.to_json())
model.save_weights('weights.h5')

with open('model.json') as f:
    model = model_from_json(f.read())
model.load_weights('weights.h5')

#ロードしたものをもう一度コンパイルする用
model.compile(loss='categorical_crossentropy',
               optimizer='adam',
               metrics=['accuracy'])

#評価部
result = model.evaluate_generator(train_generator)
print("closed test")
print('loss:',result[0])
print('accuracy:',result[1])

result = model.evaluate_generator(test_generator)
print("open test")
print('loss:',result[0])
print('accuracy:',result[1])



#学習時の様子を可視化
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'],label="training")
plt.plot(history.history['val_accuracy'],label="test")
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train','test'], loc='upper left')
#plt.ylim(0.2,0.6)
#plt.xlim(0,5)
plt.show()

plt.plot(history.history['loss'],label="training")
plt.plot(history.history['val_loss'],label="test")
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train','test'], loc='upper left')
plt.show()

試したこと

kerasのモデルにはtraining modeとtesting dataが存在し、そのせいで学習時のモデルと評価時のモデルの振る舞いが異なっていることが原因だと考えました。
そのためモデルを保存⇒再ロード⇒評価としてみたのですが、変化なしです。

補足情報(FW/ツールのバージョンなど)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • tiitoi

    2020/07/13 18:10

    訓練データに対する loss は下がっていて、評価データに対する loss は下がらないということであれば、過学習ではないかとも思えますが、その可能性は排除できているのでしょうか?

    キャンセル

  • tomoya_hatanaka

    2020/07/13 18:41

    仰るように、訓練データに対するlossは正しく減少しているが評価データに対するlossは高いままで推移している(振動すらしている)ことと、accuracyの様子から過学習と言えると思います。

    ここで見て頂きたいのが図と、その下のevaluate_generatorによって計算したloss値を見比べて頂きたいです。
    openの数値はloss,accuracy共にエポックが15回目の値を取っていると考えられますが、closedの数値はどう見ても表からかけ離れています。
    この現状と過学習を切り離して考えていたのですが、それは間違いでしょうか?

    キャンセル

  • tiitoi

    2020/07/13 20:37

    Loss のグラフと evaluate_generator() で算出される評価値が異なるというのは質問の旨だとしたら、過学習は関係ないですね。失礼しました。
    コードを見ただけだと、ちょっと原因はわからないです。
    とりあえずグラフの出力に使っている history.history['val_loss'] の最後の値と model.evaluate_generator(test_generator) で出てくる値を比較してみてはどうでしょうか?
    print('loss:',result[0])
    print(history.history['val_loss'][-1])

    もしこれらの値に違いがあるようであれば、evaluate_generator() が算出した loss と history.history['val_loss'] に格納されてる学習時に記録された loss が同じ方法で計算されたものかを確認する必要があると思います。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る