如何避免在简单的前馈网络上过度拟合

时间:2017-07-04 14:56:57

标签: machine-learning tensorflow keras prediction

使用pima indians diabetes dataset我正在尝试使用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()

经过多次尝试,我添加了辍学图层,以避免过度拟合,但没有运气。下图显示验证损失和培训损失在一个点上是分开的。

enter image description here

我还可以做些什么来优化这个网络?

更新 基于我得到的评论,我已经调整了代码:

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 here enter image description here

3 个答案:

答案 0 :(得分:13)

enter image description here

第一个例子给出了验证准确度> 75%和第二个给出精确度< 65%,如果比较100以下的时期损失,则小于<第一个为0.5,第二个为> 0.6。但第二种情况如何更好?

我的第二个案例是under-fitting:模型没有足够的学习能力。虽然第一种情况有over-fitting的问题,因为过度拟合开始时(early stopping)没有停止训练。如果训练在100个时期停止,那么两者之间的模型就会好得多。

目标应该是在看不见的数据中获得小的预测误差,并且为此增加网络的容量,直到过度拟合开始发生。

那么在这种特殊情况下如何避免over-fitting?采用early stopping

代码更改:要包含early stoppinginput 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])

Accuracyloss图表:

enter image description here

答案 1 :(得分:3)

首先,尝试添加一些正则化(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(虽然它已经很高)。你可能也不需要在很多时代内运行它 - 它会在足够长的时间后开始过度填充。

答案 2 :(得分:2)

对于像糖尿病这样的数据集,您可以使用更简单的网络。尝试减少第二层中的神经元。 (你选择tanh作为激活的具体原因是什么?)。

此外,您只需在训练中添加EarlyStopping回调:https://keras.io/callbacks/