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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1058閲覧

ImageDataGeneratorを用いた学習で検証データの学習曲線が乖離してしまう

megadaibutsu

総合スコア1

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/11/11 08:01

編集2021/11/12 02:49

前提・実現したいこと

ImageDataGeneratorによってデータ拡張を行いながらセマンティックセグメンテーションに取り組んでいるのですが、検証データの学習曲線が訓練データの学習曲線と大きく乖離してしまいます。テストデータによる予測は上手くいっており、コード自体に原因があると考えているのですがその原因を特定出来ません。どなたか気付いたことを教えて頂ければと思います。
イメージ説明

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

学習曲線が明らかにおかしくなっています。予測結果のMeanIoUは0.9程度と学習自体は上手くいっているようです。

該当のソースコード

python

1import tensorflow as tf 2from tensorflow import keras 3 4import numpy as np 5import pandas as pd 6import matplotlib.pyplot as plt 7 8from skimage import morphology 9 10# %time 11from tensorflow.keras.preprocessing.image import ImageDataGenerator 12 13tf.__version__ 14 15print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU'))) 16 17data = np.load('data_all.npz') 18X_all = data['X'] 19Y_all = data['Y'] 20 21print('Shape of X: {:}'.format(X_all.shape)) 22print('Shape of Y: {:}'.format(Y_all.shape)) 23 24for n in range(Y_all.shape[0]): 25 26 #plt.figure(figsize=(16,8)) 27 #plt.subplot(1,2,1) 28 #plt.imshow(Y_all[n,:,:]) 29 30 Y_all[n,:,:] = morphology.dilation(Y_all[n,:,:],morphology.square(7)) 31 32 #plt.subplot(1,2,2) 33 #plt.imshow(Y_all[n,:,:]) 34 #plt.show() 35 36X_all = X_all / 255.0 37 38num_all = 48 39 40np.random.seed(6) 41id_all = np.random.choice(num_all, num_all, replace=False) 42id_test = id_all[0:5] 43id_valid = id_all[5:10] 44id_train = id_all[10:48] 45X_test = X_all[id_test] 46X_train = X_all[id_train] 47X_valid = X_all[id_valid] 48Y_test = Y_all[id_test] 49Y_train = Y_all[id_train] 50Y_valid = Y_all[id_valid] 51 52print('Shape of Y_train: {:}'.format(Y_train.shape)) 53print('Shape of Y_valid: {:}'.format(Y_valid.shape)) 54print('Shape of Y_test: {:}'.format(Y_test.shape)) 55 56Y_test = Y_test[:,:,:,None] 57Y_train = Y_train[:,:,:,None] 58Y_valid = Y_valid[:,:,:,None] 59 60print('Shape of Y_train: {:}'.format(Y_train.shape)) 61print('Shape of Y_valid: {:}'.format(Y_valid.shape)) 62print('Shape of Y_test: {:}'.format(Y_test.shape)) 63 64def image_augmentation(imgs, masks, batch_size, seed): 65 # create two instances with the same arguments 66 # create dictionary with the input augmentation values 67 data_gen_args = dict(featurewise_center=False, 68 featurewise_std_normalization=False, 69 rotation_range=10, 70 horizontal_flip=True,) 71 72 ## use this method with both images and masks 73 image_datagen = ImageDataGenerator(**data_gen_args) 74 mask_datagen = ImageDataGenerator(**data_gen_args) 75 76 ## fit the augmentation model to the images and masks with the same seed 77 image_datagen.fit(imgs, augment=True, seed=seed) 78 mask_datagen.fit(masks, augment=True, seed=seed) 79 80 ## set the parameters for the data to come from (images) 81 image_generator = image_datagen.flow(imgs, 82 shuffle=True, 83 batch_size=batch_size, 84 save_to_dir=None, 85 save_prefix='out_image', 86 seed=seed) 87 88 ## set the parameters for the data to come from (masks) 89 mask_generator = mask_datagen.flow(masks, 90 shuffle=True, 91 batch_size=batch_size, 92 save_to_dir=None, 93 save_prefix='out_mask', 94 seed=seed) 95 96 # combine generators into one which yields image and masks 97 train_generator = zip(image_generator, mask_generator) 98 99 ## return the train generator for input in the CNN 100 return train_generator 101 102batch_size = 4 103epoch_num =1000 104seed = 6 105 106train_generator = image_augmentation(X_train, Y_train,batch_size,seed) 107valid_generator = image_augmentation(X_valid, Y_valid,batch_size,seed) 108 109#入力層 110input_ = keras.layers.Input(shape=X_train.shape[1:]) 111 112#2次元畳み込み層 113zero1_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(input_) 114conv1_1 = keras.layers.Convolution2D(9, activation='relu', kernel_size=3)(zero1_1) 115zero1_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(conv1_1) 116conv1_2 = keras.layers.Convolution2D(9, activation='relu', kernel_size=3)(zero1_2) 117 118#2次元マックスプーリング層 119maxpool1 = keras.layers.MaxPool2D(2)(conv1_2) 120 121#2次元畳み込み層 122zero2_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(maxpool1) 123conv2_1 = keras.layers.Convolution2D(18, activation='relu', kernel_size=3)(zero2_1) 124zero2_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(conv2_1) 125conv2_2 = keras.layers.Convolution2D(18, activation='relu', kernel_size=3)(zero2_2) 126 127#入力からの2次元畳み込み層 128conv_2 = keras.layers.Convolution2D(1, activation='relu', kernel_size=1)(conv2_2) 129 130#バッチ正規化 131root2_1 = keras.layers.BatchNormalization()(conv_2) 132 133#2次元マックスプーリング層 134maxpool2 = keras.layers.MaxPool2D(2)(conv2_2) 135 136#2次元畳み込み層 137zero3_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(maxpool2) 138conv3_1 = keras.layers.Convolution2D(36, activation='relu', kernel_size=3)(zero3_1) 139zero3_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(conv3_1) 140conv3_2 = keras.layers.Convolution2D(36, activation='relu', kernel_size=3)(zero3_2) 141 142#入力からの2次元畳み込み層 143conv_3 = keras.layers.Convolution2D(1, activation='relu', kernel_size=1)(conv3_2) 144 145#バッチ正規化 146root3_1 = keras.layers.BatchNormalization()(conv_3) 147 148#2次元マックスプーリング層 149maxpool3 = keras.layers.MaxPool2D(2)(conv3_2) 150 151zero4_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(maxpool3) 152conv4_1 = keras.layers.Convolution2D(72, activation='relu', kernel_size=3)(zero4_1) 153zero4_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(conv4_1) 154conv4_2 = keras.layers.Convolution2D(72, activation='relu', kernel_size=3)(zero4_2) 155 156#2次元アップサンプリング 157upsample3 = keras.layers.UpSampling2D(2)(conv4_2) 158 159#バッチ正規化 160root3_2 = keras.layers.BatchNormalization()(upsample3) 161 162#別ルートのネットワーク出力の結合 163concat3 = keras.layers.Concatenate()([root3_1, root3_2]) 164 165# 2次元逆畳み込み層(deconvolution layer) 166 167dezero3_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(concat3) 168deconv3_1 = keras.layers.Convolution2D(36, activation='relu', kernel_size=3)(dezero3_1) 169dezero3_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(deconv3_1) 170deconv3_2 = keras.layers.Convolution2D(36, activation='relu', kernel_size=3)(dezero3_2) 171 172#2次元アップサンプリング 173upsample2 = keras.layers.UpSampling2D(2)(deconv3_2) 174 175#バッチ正規化 176root2_2 = keras.layers.BatchNormalization()(upsample2) 177 178#別ルートのネットワーク出力の結合 179concat2 = keras.layers.Concatenate()([root2_1, root2_2]) 180 181# 2次元逆畳み込み層(deconvolution layer) 182dezero2_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(concat2) 183deconv2_1 = keras.layers.Convolution2D(18, activation='relu', kernel_size=3)(dezero2_1) 184dezero2_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(deconv2_1) 185deconv2_2 = keras.layers.Convolution2D(18, activation='relu', kernel_size=3)(dezero2_2) 186 187#2次元アップサンプリング 188upsample1 = keras.layers.UpSampling2D(2)(deconv2_2) 189 190# 2次元逆畳み込み層(deconvolution layer) 191dezero1_1 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(upsample1) 192deconv1_1 = keras.layers.Convolution2D(9, activation='relu', kernel_size=3)(dezero1_1) 193dezero1_2 = keras.layers.ZeroPadding2D(padding=(1, 1), data_format=None)(deconv1_1) 194deconv1_2 = keras.layers.Convolution2D(9, activation='relu', kernel_size=3)(dezero1_2) 195 196#バッチ正規化 197root1_1 = keras.layers.BatchNormalization()(deconv1_2) 198 199#入力からの2次元畳み込み層 200conv_1 = keras.layers.Convolution2D(1, activation='relu', kernel_size=1)(input_) 201 202#バッチ正規化 203root1_2 = keras.layers.BatchNormalization()(conv_1) 204 205#別ルートのネットワーク出力の結合 206concat1 = keras.layers.Concatenate()([root1_1, root1_2]) 207 208#クラスラベル判定のための層 209output = keras.layers.Convolution2D(2, activation='softmax', kernel_size=1)(concat1) 210 211model = keras.Model(inputs=[input_], outputs=[output]) 212 213class UpdatedMeanIoU(tf.keras.metrics.MeanIoU): 214 def __init__(self, 215 y_true=None, 216 y_pred=None, 217 num_classes=None, 218 name=None, 219 dtype=None): 220 super(UpdatedMeanIoU, self).__init__(num_classes = num_classes,name=name, dtype=dtype) 221 222 def update_state(self, y_true, y_pred, sample_weight=None): 223 y_pred = tf.math.argmax(y_pred, axis=-1) 224 return super().update_state(y_true, y_pred, sample_weight) 225 226#検証誤差の小さくなるモデルを保存するコールバック関数 227checkpoint_cb = keras.callbacks.ModelCheckpoint('U_net_best.h5', save_best_only=True) 228 229#学習の設定 230model.compile(loss='sparse_categorical_crossentropy', 231 optimizer=keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999), 232 metrics=[UpdatedMeanIoU(num_classes=2)]) 233 234history = model.fit_generator(train_generator, 235 epochs = epoch_num, 236 steps_per_epoch = X_train.shape[0]//batch_size, 237 validation_steps = X_valid.shape[0]//batch_size, 238 shuffle = True, 239 verbose = 1, 240 validation_data = valid_generator , 241 callbacks = [checkpoint_cb]) 242 243#モデルの保存 244model.save('U_net1111_6.h5') 245 246hist_df = pd.DataFrame(history.history) 247hist_df.to_csv('history1111_6.csv')

試したこと

ImagedataGenerator無しでの学習、
イメージ説明
データ数の配分変更(訓練データ33枚、検証データ10枚)
ImagedataGeneratorでデータ拡張無し(バッチ数1)での学習
イメージ説明

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

Python3.6、Tensorflow-gpu2.6
ここにより詳細な情報を記載してください。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jbpb0

2021/11/11 08:12 編集

ImagedataGeneratorの有無で、使ってるデータは全く同じものですか? > ImageDataGeneratorによってデータ拡張を行いながら データ拡張をしてるのは、ImagedataGenerator有りの方だけですか?
jbpb0

2021/11/11 08:11

グラフのオレンジや青の線も、ImagedataGeneratorの有無で違うように見えるので、検証データ(赤と緑の線)だけおかしいというわけではないような
megadaibutsu

2021/11/11 08:16

はい、全く同じものになります。ImagedataGeneratorは精度向上と過学習防止の目的で利用しており、拡張前の学習曲線は過学習を起こしていると判断しています。なので、おかしいという指摘はその通りです。ただ、拡張後で学習データに対して検証データがここまで乖離しているのは拡張前後で比較しても何か問題があるように見えるため、質問させて頂きました。
jbpb0

2021/11/11 08:21

データ拡張を全くやらず、ImagedataGeneratorの有無しか違わない状態で比較したら、どうなるのでしょうか? それで、結果が大体同じになるのなら、データ拡張が精度を落としてるのではないですかね それの影響が、学習データ(オレンジと青線)よりも検証データ(赤と緑線)の方がより大きく影響受ける、的な
megadaibutsu

2021/11/11 08:26

ありがとうございます、一度ImagedataGeneratorで拡張無しの状態で学習を試してみます
megadaibutsu

2021/11/12 02:52

実際に行ってみた結果、学習曲線がそこまで乖離しない結果となりました。これを見ると拡張によって検証データがより大きく影響を受けた結果ということになるのでしょうか……。
jbpb0

2021/11/12 03:24

データ拡張は、学習データだけですか? 検証データもやってますか?
megadaibutsu

2021/11/12 03:27

学習データと検証データの両方でやっています
jbpb0

2021/11/12 03:55

詳細知らないので想像ですが、検証データの拡張で生成した画像に類似の画像が、学習データにはあまりない、のではないですかね 学習データの拡張で生成した画像と、検証データの拡張で生成した画像が、あまり似てないので、データ拡張の結果として、学習データと検証データが乖離してしまった データ拡張された学習データに「過学習」してしまったので、検証データの推定精度が下がった みたいな もし上記が起きてるのなら、検証データの拡張は今のままで、学習データの拡張で作成する画像数を大幅に増やしたら、学習データの性能と検証データの性能が近くなると思います 検証データの拡張された画像と類似の画像が、学習データの拡張で発生されやすくなるので ただし、学習データのバリエーションが大幅に増えると、学習が難しくなって、学習データと検証データの性能は近くなるけど、どちらも性能が低下する、となる可能性があります AIの性能と、データ拡張のバリエーションの兼ね合い次第ですが
guest

回答1

0

ベストアンサー

データ拡張を全くやらず、ImagedataGeneratorの有無しか違わない状態で比較して、結果が近くなるのでしたら、データ拡張が精度を落としてるのではないですかね

投稿2021/11/15 06:36

jbpb0

総合スコア7651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

megadaibutsu

2021/11/16 05:48

ありがとうございます、拡張前後の結果などを考え、この件に関してはそのような形で結論付けようと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問