如何避免在简单的前馈网络上过度拟合
How to avoid overfitting on a simple feed forward network
使用 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()
经过几次尝试,我添加了 dropout 层以避免过度拟合,但没有成功。下图显示验证损失和训练损失在一点分开。
我还能做些什么来优化这个网络?
更新:
根据我得到的评论,我已经像这样调整了代码:
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 个时期的图表
对于像糖尿病这样的数据集,您可以使用更简单的网络。尝试减少第二层的神经元。 (您选择 tanh 作为那里的激活有什么具体原因吗?)。
此外,您只需在训练中添加 EarlyStopping 回调即可:https://keras.io/callbacks/
首先,尝试添加一些正则化 (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(尽管已经很高)。您可能也不需要 运行 如此多的 epoch - 它会在足够长的时间后开始过度拟合。
第一个示例给出的验证准确度 > 75%,第二个示例给出的准确度 < 65%,如果比较低于 100 的时期的损失,第一个和第二个的损失小于 < 0.5 > 0.6。但是第二种情况如何更好呢?
第二个对我来说是 under-fitting
的情况:模型没有足够的学习能力。而第一种情况有over-fitting
的问题,因为它的训练在过拟合开始时没有停止(early stopping
)。如果训练在 100 个 epoch 时停止,那么与两者相比,这将是一个更好的模型。
目标应该是在看不见的数据中获得较小的预测误差,为此您可以增加网络的容量,直到超过该点开始发生过度拟合。
那么在这种特殊情况下如何避免 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
图表:
使用 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()
经过几次尝试,我添加了 dropout 层以避免过度拟合,但没有成功。下图显示验证损失和训练损失在一点分开。
我还能做些什么来优化这个网络?
更新: 根据我得到的评论,我已经像这样调整了代码:
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 个时期的图表
对于像糖尿病这样的数据集,您可以使用更简单的网络。尝试减少第二层的神经元。 (您选择 tanh 作为那里的激活有什么具体原因吗?)。
此外,您只需在训练中添加 EarlyStopping 回调即可:https://keras.io/callbacks/
首先,尝试添加一些正则化 (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(尽管已经很高)。您可能也不需要 运行 如此多的 epoch - 它会在足够长的时间后开始过度拟合。
第一个示例给出的验证准确度 > 75%,第二个示例给出的准确度 < 65%,如果比较低于 100 的时期的损失,第一个和第二个的损失小于 < 0.5 > 0.6。但是第二种情况如何更好呢?
第二个对我来说是 under-fitting
的情况:模型没有足够的学习能力。而第一种情况有over-fitting
的问题,因为它的训练在过拟合开始时没有停止(early stopping
)。如果训练在 100 个 epoch 时停止,那么与两者相比,这将是一个更好的模型。
目标应该是在看不见的数据中获得较小的预测误差,为此您可以增加网络的容量,直到超过该点开始发生过度拟合。
那么在这种特殊情况下如何避免 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
图表: