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

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

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

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

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

Python

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

Q&A

解決済

1回答

1771閲覧

CNNの2値分類で精度が変化しない

yukawakota

総合スコア14

Keras

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

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

Python

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

0グッド

0クリップ

投稿2019/12/16 04:11

前提・実現したいこと

CNNを用いて自前データセットの画像の2値分類を行おうと思っています。
データセットが不均衡なので(クラス0:クラス1=8:1くらい)、クラス1のデータを画像のデータ拡張によってオーバーサンプリングしています。

該当のソースコード

python

1import os 2import numpy as np 3import keras 4from keras import layers 5from keras import models 6from keras import optimizers 7from keras.preprocessing.image import ImageDataGenerator 8from keras.utils import plot_model 9import tensorflow.keras.backend as K 10 11from sklearn.utils import shuffle 12 13import pandas as pd 14 15import matplotlib 16matplotlib.use('Agg') 17import matplotlib.pyplot as plt 18plt.style.use('ggplot') 19 20from datasets import make_dir, extract_data 21 22def cnn_model(image_size): 23 model = models.Sequential() 24 model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 1))) 25 model.add(layers.normalization.BatchNormalization()) 26 model.add(layers.MaxPooling2D((2, 2))) 27 model.add(layers.Conv2D(64, (3, 3), activation='relu')) 28 model.add(layers.MaxPooling2D((2, 2))) 29 model.add(layers.Conv2D(64, (3, 3), activation='relu')) 30 model.add(layers.Flatten()) 31 model.add(layers.Dropout(0.5)) 32 model.add(layers.Dense(30, activation='relu')) 33 model.add(layers.normalization.BatchNormalization()) 34 model.add(layers.Dense(1, activation='sigmoid')) 35 return model 36 37def train(x_train, y_train, x_val, y_val, image_size, output_dir, fold_num=5): 38 model =cnn_model(image_size) 39 model.summary() 40 plot_model(model, show_shapes=True, to_file=output_dir + '/model.png') 41 history_list = [] 42 csv_dir = os.path.join(output_dir, 'training_result_csv') 43 make_dir(csv_dir) 44 model_dir = os.path.join(output_dir, 'saved_model') 45 make_dir(model_dir) 46 # データの水増し(Data Augmentation) 47 datagen = ImageDataGenerator(rescale=1./255, 48 rotation_range=40, 49 width_shift_range=0.2, 50 height_shift_range=0.2, 51 shear_range=0.2, 52 zoom_range=0.2, 53 horizontal_flip=True) 54 x_0 = x_train[np.where(y_train==0)[0]] 55 x_1 = x_train[np.where(y_train==1)[0]] 56 y_0 = y_train[np.where(y_train==0)[0]] 57 x_1, y_1 = over_sampling(x_1, datagen, 8, 1) 58 x_train = np.concatenate([x_0, x_1]) 59 y_train = np.concatenate([y_0, y_1]) 60 x_train, y_train = shuffle(x_train, y_train, random_state=0) 61 # 水増し画像を訓練用画像の形式に合わせる 62 datagen.fit(x_train, augment=True, rounds=10) 63 filename = os.path.join(csv_dir, 'training_result.csv') 64 callbacks_list = [keras.callbacks.CSVLogger(filename)] 65 model.compile(loss='binary_crossentropy', 66 optimizer=optimizers.Adam(lr=1e-4), 67 metrics=['acc']) 68 history = model.fit_generator(datagen.flow(x_train, y_train, batch_size=32), 69 steps_per_epoch=x_train.shape[0] // 32, 70 epochs=20, 71 verbose=1, 72 validation_data=(x_val, y_val), 73 callbacks=callbacks_list) 74 history_list.append(history) 75 model.save(os.path.join(model_dir, 'saved_model.h5')) 76 return history_list 77 78def draw_graph(history_list, output_dir): 79 for i, history in enumerate(history_list): 80 acc = history.history['acc'] 81 val_acc = history.history['val_acc'] 82 loss = history.history['loss'] 83 val_loss = history.history['val_loss'] 84 85 epochs = range(1, len(acc) + 1) 86 87 plt.figure() 88 plt.plot(epochs, acc, 'bo', label='Training acc') 89 plt.plot(epochs, val_acc, 'b', label='Validation acc') 90 plt.title('Training and validation accuracy') 91 plt.legend() 92 plt.savefig(output_dir + '/acc{}.png'.format(i)) 93 plt.show() 94 95 plt.figure() 96 plt.plot(epochs, loss, 'bo', label='Training loss') 97 plt.plot(epochs, val_loss, 'b', label='Validation loss') 98 plt.title('Training and validation loss') 99 plt.legend() 100 plt.savefig(output_dir + '/loss{}.png'.format(i)) 101 plt.show() 102 103def over_sampling(datas, datagen, num, label_num): 104 imgs = [] 105 label_list = [] 106 for x in datas: 107 x = np.expand_dims(x, axis=0) 108 for d in datagen.flow(x, batch_size=1): 109 d = np.squeeze(d, axis=0) 110 imgs.append(d) 111 label_list.append(label_num) 112 if (len(imgs) % num) == 0: 113 break 114 return np.array(imgs), np.expand_dims(np.array(label_list), axis=-1) 115 116if __name__ == '__main__': 117 train_dir = 'datasets/train_binary/' 118 valid_dir = 'datasets/valid_binary/' 119 output_dir = 'model_out_shuffle' 120 classes = ['0', '1'] 121 image_size = 150 122 123 make_dir(output_dir) 124 x_train, y_train = extract_data(train_dir, classes, image_size) 125 x_val, y_val = extract_data(valid_dir, classes, image_size) 126 history_list = train(x_train, y_train, x_val, y_val, image_size, output_dir) 127 graph_dir = os.path.join(output_dir, 'training_result_graph') 128 make_dir(graph_dir) 129 draw_graph(history_list, graph_dir) 130 df_dir = os.path.join(output_dir, 'df_csv') 131 make_dir(df_dir) 132 for i, history in enumerate(history_list): 133 df = pd.DataFrame(history.history) 134 filename = os.path.join(df_dir, 'training{}_history.csv'.format(i+1)) 135 df.to_csv(filename) 136

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

実際に学習させてログを見ると、二回目のエポックから訓練データの精度は1.0、検証データの精度は0.87で停止してしまっています。

Epoch 1/20 53/53 [==============================] - 118s 2s/step - loss: 0.0361 - acc: 0.9870 - val_loss: 2.5961 - val_acc: 0.8700 Epoch 2/20 53/53 [==============================] - 118s 2s/step - loss: 0.0029 - acc: 1.0000 - val_loss: 4.4108 - val_acc: 0.8700 Epoch 3/20 53/53 [==============================] - 117s 2s/step - loss: 0.0044 - acc: 0.9994 - val_loss: 7.1868 - val_acc: 0.8700 Epoch 4/20 53/53 [==============================] - 115s 2s/step - loss: 0.0028 - acc: 1.0000 - val_loss: 12.1159 - val_acc: 0.8700 Epoch 5/20 53/53 [==============================] - 115s 2s/step - loss: 0.0018 - acc: 1.0000 - val_loss: 18.7604 - val_acc: 0.8700 Epoch 6/20 53/53 [==============================] - 116s 2s/step - loss: 0.0022 - acc: 1.0000 - val_loss: 27.9707 - val_acc: 0.8700 Epoch 7/20 53/53 [==============================] - 116s 2s/step - loss: 0.0021 - acc: 1.0000 - val_loss: 40.4534 - val_acc: 0.8700 Epoch 8/20 53/53 [==============================] - 115s 2s/step - loss: 0.0014 - acc: 1.0000 - val_loss: 54.9640 - val_acc: 0.8700 Epoch 9/20 53/53 [==============================] - 115s 2s/step - loss: 0.0015 - acc: 1.0000 - val_loss: 72.0444 - val_acc: 0.8700 Epoch 10/20 53/53 [==============================] - 117s 2s/step - loss: 0.0014 - acc: 1.0000 - val_loss: 90.2816 - val_acc: 0.8700 Epoch 11/20 53/53 [==============================] - 120s 2s/step - loss: 0.0012 - acc: 1.0000 - val_loss: 105.6784 - val_acc: 0.8700 Epoch 12/20 53/53 [==============================] - 117s 2s/step - loss: 0.0014 - acc: 1.0000 - val_loss: 121.3914 - val_acc: 0.8700 Epoch 13/20 53/53 [==============================] - 115s 2s/step - loss: 0.0010 - acc: 1.0000 - val_loss: 140.8129 - val_acc: 0.8700 Epoch 14/20 53/53 [==============================] - 116s 2s/step - loss: 0.0012 - acc: 1.0000 - val_loss: 160.8408 - val_acc: 0.8700 Epoch 15/20 53/53 [==============================] - 118s 2s/step - loss: 9.9551e-04 - acc: 1.0000 - val_loss: 169.9402 - val_acc: 0.8700 Epoch 16/20 53/53 [==============================] - 116s 2s/step - loss: 0.0013 - acc: 1.0000 - val_loss: 181.2626 - val_acc: 0.8700 Epoch 17/20 53/53 [==============================] - 116s 2s/step - loss: 0.0012 - acc: 1.0000 - val_loss: 178.5618 - val_acc: 0.8700 Epoch 18/20 53/53 [==============================] - 116s 2s/step - loss: 8.5294e-04 - acc: 1.0000 - val_loss: 183.2046 - val_acc: 0.8700 Epoch 19/20 53/53 [==============================] - 123s 2s/step - loss: 9.1750e-04 - acc: 1.0000 - val_loss: 187.8404 - val_acc: 0.8700 Epoch 20/20 53/53 [==============================] - 123s 2s/step - loss: 7.0443e-04 - acc: 1.0000 - val_loss: 179.0444 - val_acc: 0.8700

試したこと

検証の精度0.87はクラス0とクラス1の比なので、おそらくすべてクラス0と予測して出力しているだろうことはわかりました。しかし、訓練の精度が1.0で停止している理由がわかりません。また、その解決策があればよろしくおねがいします。

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

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

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

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

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

Q71

2019/12/16 11:51

訓練が1.0つまり100%正解が出ているなら、それ以上調整する必要はないですよ。
yukawakota

2019/12/16 12:57

追記ありがとうございます。 検証に使っているデータで混同行列を出力し、確認してみたところ以下のようになりました。 [[174 0] [ 26 0]] これではすべてのデータをクラス0と予測しているようです。なので、訓練データでは良いのですがその他のデータでは分類機として機能していないので、強力な過学習が発生しているのではないかとも思っています。過学習対策の解決策などあれば追記をよろしくおねがいします。
Q71

2019/12/16 13:58

conv max pool conv max pool conv flat * 2 で間違いないでしょうか。 畳み込み3層は薄いです。6層は重ねてみましょう。 ちゃんとどんな特徴を取ったか確認しましょう。
yukawakota

2019/12/16 14:52

層が薄いと過学習の原因になるのですね。。。 層を増やしてハイパーパラメータを試行錯誤してみます。
Q71

2019/12/16 23:27

過学習というか、学習できていません。Faster R-CNNやGrad-CAMの論文になにを学習したかを判断するヒントが書かれています。読んでみましょう。
guest

回答1

0

自己解決

自分でデータをファイルから読み込んだ部分で画像を1./255で正規化したあとに、kerasのDatageneratorの方でも同じ処理を二重で行ってしまっており、trainのデータとvalidationのデータで正規化のスケーリングが一致していないのがtrainでの精度が1.0で停滞してしまっていた原因でした。最終的にはImageDataGenerator.flow_from_directoryで画像の前処理を一本化することで解決しました。不均衡データに対する不具合はunder samplingや、ハイパーパラメータの調整でより良い精度を目指します。

投稿2019/12/17 11:37

yukawakota

総合スコア14

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問