web-dev-qa-db-ja.com

単純なフィードフォワードネットワークで過剰適合を回避する方法

pima indians糖尿病データセットを使用して Kerasを使用して正確なモデルを構築しようとしています。次のコードを書きました。

# Visualize training history
from keras import callbacks
from keras.layers import Dropout

tb = callbacks.TensorBoard(log_dir='/.logs', histogram_freq=10, batch_size=32,
                           write_graph=True, write_grads=True, write_images=False,
                           embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)
# Visualize training history
from keras.models import Sequential
from keras.layers import Dense
import matplotlib.pyplot as plt
import numpy

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load pima indians dataset
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# split into input (X) and output (Y) variables
X = dataset[:, 0:8]
Y = dataset[:, 8]
# create model
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation='relu', name='first_input'))
model.add(Dense(500, activation='tanh', name='first_hidden'))
model.add(Dropout(0.5, name='dropout_1'))
model.add(Dense(8, activation='relu', name='second_hidden'))
model.add(Dense(1, activation='sigmoid', name='output_layer'))

# Compile model
model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

# Fit the model
history = model.fit(X, Y, validation_split=0.33, epochs=1000, batch_size=10, verbose=0, callbacks=[tb])
# list all data in history
print(history.history.keys())
# summarize history for accuracy
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# summarize history for loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

何度か試した後、オーバーフィットを避けるためにドロップアウトレイヤーを追加しましたが、運はありません。次のグラフは、検証損失とトレーニング損失が1つのポイントで分離することを示しています。

enter image description here

このネットワークを最適化するために他に何ができますか?

UPDATE:私が得たコメントに基づいて、次のようにコードを調整しました:

model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', kernel_regularizer=regularizers.l2(0.01),
                activity_regularizer=regularizers.l1(0.01), activation='relu',
                name='first_input'))  # added regularizers
model.add(Dense(8, activation='relu', name='first_hidden'))  # reduced to 8 neurons
model.add(Dropout(0.5, name='dropout_1'))
model.add(Dense(5, activation='relu', name='second_hidden'))
model.add(Dense(1, activation='sigmoid', name='output_layer'))

500エポックのグラフはこちら

enter image description hereenter image description here

11
Shlomi Schwartz

enter image description here

最初の例では検証の精度が75%を超え、2番目の例では精度が65%未満であり、100未満のエポックの損失を比較すると、最初の例では<0.5未満であり、2番目の例では> 0.6でした。しかし、2番目のケースはどのように優れていますか?.

私にとって2番目は、under-fittingの場合です。モデルには学習するのに十分な能力がありません。最初のケースでは、オーバーフィッティングの開始時にトレーニングが停止しなかったため、over-fittingの問題があります(early stopping)。たとえば100エポックでトレーニングが停止された場合、2つのモデルに比べてはるかに優れたモデルになります。

目標は、目に見えないデータで小さな予測エラーを取得することであり、そのためにオーバーフィットが発生し始めるポイントまでネットワークの容量を増やします。

それでは、この特定のケースでover-fittingを避ける方法は? early stoppingを採用します。

コードの変更:early stoppingおよびinput scalingを含める。

 # input scaling
 scaler = StandardScaler()
 X = scaler.fit_transform(X)

 # Early stopping  
 early_stop = EarlyStopping(monitor='val_loss', min_delta=0, patience=3, verbose=1, mode='auto')

 # create model - almost the same code
 model = Sequential()
 model.add(Dense(12, input_dim=8, activation='relu', name='first_input'))
 model.add(Dense(500, activation='relu', name='first_hidden'))
 model.add(Dropout(0.5, name='dropout_1'))
 model.add(Dense(8, activation='relu', name='second_hidden'))
 model.add(Dense(1, activation='sigmoid', name='output_layer')))

 history = model.fit(X, Y, validation_split=0.33, epochs=1000, batch_size=10, verbose=0, callbacks=[tb, early_stop])

Accuracyおよびlossグラフ:

enter image description here

13
vijay m

まず、次のコードのように、いくつかの正則化( https://keras.io/regularizers/ )を追加してみてください。

model.add(Dense(12, input_dim=12,
            kernel_regularizer=regularizers.l2(0.01),
            activity_regularizer=regularizers.l1(0.01)))

また、ネットワークサイズを小さくするようにしてください。つまり、500個のニューロンの隠れ層は必要ありません。表現力を減らすためにそれを取り出してみてください。また、reluアクティベーションのみを使用します。また、ドロップアウト率を0.75のような値に上げてみてください(既に高い値ですが)。おそらく、これを多くのエポックで実行する必要はありません。十分な時間が経つと過剰になり始めます。

3
CoolPenguin

糖尿病のようなデータセットの場合、はるかに単純なネットワークを使用できます。 2番目の層のニューロンを減らすようにしてください。 (そこにアクティベーションとしてtanhを選択した具体的な理由はありますか?)。

さらに、トレーニングにEarlyStoppingコールバックを追加するだけです。 https://keras.io/callbacks/

2
petezurich