前提・実現したいこと
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
ここにより詳細な情報を記載してください。
回答1件
あなたの回答
tips
プレビュー