长短期记忆(LSTM)系列_LSTM的建模方法(3)——如何判断LSTM模型的过度拟合和欠拟合

导读:

本文主要讲了一些模型中一个常见的问题,训练不足和过度拟合。

过度拟合指的是由于训练数据过少,或者对训练集训练的次数过多,导致模型的结果不是找到所有数据的一般共有特性,而是仅对训练数据进行了特征提取。换句话说,这个模型已经记住了所有的训练数据,对训练数据的预测效果非常好,但对其他数据的预测效果非常差。

对于训练不足的情况来说,可以通过增加网络中的节点,或者增加网络的训练周期来达到。

对于过度拟合的情况来说,可以通多减少或控制训练周期,在数据出现拐点前,停止对网络的训练来达到。

最后为了检验训练效果,我们可以多次训练并将训练结果的图像画出来,最终诊断模型训练的效果如何,是否稳定可行。

1.Keras模型训练中的history

通过查看模型的性能,您可以了解很多关于模型行为的知识。

通过调用fit()函数来训练LSTM模型。此函数返回一个名为history的变量,该变量包含损失的跟踪以及在编译模型期间指定的任何其他度量,在周期结束时记录数据。

例如,如果编译模型以优化对数损失(binary_crossentropy)并测量每个时期的准确度,则将计算对数损失和准确度并记录在每个训练周期的历史记录中。

每个分数都通过调用fit()返回的历史对象中的键来访问。默认情况下,在拟合模型时优化的损耗称为“ 损耗 ”,精度称为“ acc ”。

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(X, Y, epochs=100)
print(history.history['loss'])
print(history.history['acc'])

 Keras还允许您在拟合模型时指定单独的验证数据集,也可以使用相同的损失和指标进行评估。这可以通过在fit()上设置validation_split参数来使用一部分训练数据作为验证数据集来完成。validation_split参数指的是从训练集中选出一部分比例的数据,来进行测试。

history = model.fit(X, Y, epochs=100, validation_split=0.33)

这也可以通过设置validation_data参数并传递X和y数据集的元组来完成。
history = model.fit(X, Y, epochs=100, validation_data=(valX, valY))

带有val_的参数,是验证数据集返回的验证结果。

...
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(X, Y, epochs=100, validation_split=0.33)
print(history.history['loss'])
print(history.history['acc'])
print(history.history['val_loss'])
print(history.history['val_acc'])

2.诊断图

LSTM模型的培训历史记录可用于诊断模型的行为。

您可以使用Matplotlib库绘制模型的性能。例如,您可以将训练损失与测试损失一起绘制如下:

from matplotlib import pyplot
...
history = model.fit(X, Y, epochs=100, validation_data=(valX, valY))
pyplot.plot(history.history['loss'])
pyplot.plot(history.history['val_loss'])
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'validation'], loc='upper right')
pyplot.show()

创建和查看这些图可以帮助您了解可能的新配置,以便从模型中获得更好的性能。

接下来,我们将看一些例子。我们将考虑列车上的模型技能和最小化损失的验证集。您可以使用对您的问题有意义的所有指标。

3.不合格的例子

欠适应模型被证明在训练数据集上表现良好而在测试数据集上表现不佳。

这可以从训练损失低于验证损失的图中诊断出来,并且验证损失具有表明可以进一步改进的趋势。

下面提供了一个不足的LSTM模型的小例子。代码中history = model.fit(X, y, epochs=100, validation_data=(valX, valY), shuffle=False)这一行epochs=100,训练周期只有100个,这是明显不够的。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array

# return training data
def get_train():
	seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# return validation data
def get_val():
	seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation='linear'))
# compile model
model.compile(loss='mse', optimizer='adam')
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=100, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history['loss'])
pyplot.plot(history.history['val_loss'])
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'validation'], loc='upper right')
pyplot.show()

运行此示例会生成列车和验证损失图,显示欠装模型的特征。在这种情况下,可以通过增加训练时期的数量来改善性能。

在这种情况下,可以通过增加训练时期的数量来改善性能。

显示一个适合模型的诊断线剧情

                                                                                        显示一个适合模型的诊断线剧情

或者,如果训练集上的表现优于验证集并且性能已经趋于平稳,则模型可能不合适。以下是一个例子

以下是具有不足的存储器单元的不合格模型的代码,很明显代码中model.add(LSTM(1, input_shape=(1,1)))这一行标识的中间层节点只有1个,这是不够的

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array

# return training data
def get_train():
	seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((5, 1, 1))
	return X, y

# return validation data
def get_val():
	seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# define model
model = Sequential()
model.add(LSTM(1, input_shape=(1,1)))
model.add(Dense(1, activation='linear'))
# compile model
model.compile(loss='mae', optimizer='sgd')
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=300, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history['loss'])
pyplot.plot(history.history['val_loss'])
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'validation'], loc='upper right')
pyplot.show()

运行此示例显示了看似欠配置的模型的特征。在这种情况下,可以通过增加模型的节点容量来改善性能,例如隐藏层中的存储器单元的数量或隐藏层的数量。

通过状态显示适合模型的诊断线图

                                                                                通过状态显示适合模型的诊断线图

4.合格的例子

非常合适的情况是模型的性能在列车和验证集上都很好。

这可以从训练和验证损失减少并稳定在同一点附近的地块诊断出来。

下面的小例子展示了一个非常合格的LSTM模型。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array

# return training data
def get_train():
	seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((5, 1, 1))
	return X, y

# return validation data
def get_val():
	seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation='linear'))
# compile model
model.compile(loss='mse', optimizer='adam')
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=800, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history['loss'])
pyplot.plot(history.history['val_loss'])
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'validation'], loc='upper right')
pyplot.show()

运行该示例会创建一个显示列车和验证丢失会议的线图。

理想情况下,我们希望尽可能看到这样的模型性能,尽管这可能无法解决大量数据的挑战。

显示适合模型的诊断线图

                                                                                  显示适合模型的诊断线图

5.过度拟合示例

过度拟合模型是训练组上的性能良好并且持续改进的模型,而验证组上的性能改善到某一点然后开始降级。

这可以从训练损失向下倾斜并且验证损失向下倾斜,到达拐点并且再次开始向上倾斜的图中诊断出来。

下面的示例演示了一个过度拟合的LSTM模型。在history = model.fit(X, y, epochs=1200, validation_data=(valX, valY), shuffle=False)这段代码中,epochs=1200,这个数值设置过大,导致了训练出现过拟合现象。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array

# return training data
def get_train():
	seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((5, 1, 1))
	return X, y

# return validation data
def get_val():
	seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation='linear'))
# compile model
model.compile(loss='mse', optimizer='adam')
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=1200, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history['loss'][500:])
pyplot.plot(history.history['val_loss'][500:])
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.legend(['train', 'validation'], loc='upper right')
pyplot.show()

运行此示例会创建一个图表,显示过度拟合模型的验证丢失中的特征拐点。这可能是太多训练周期的标志。

在这种情况下,模型训练可以在拐点处停止。或者,可以增加训练数据的数量。

显示适合模型的诊断线剧情

                                                                          显示适合模型的诊断线剧情

6.多次运行示例

LSTM是随机的,这意味着每次运行都会获得不同的诊断图。

多次重复诊断运行(例如5,10或30)可能很有用。然后可以绘制来自每次运行的训练和验证曲线,以更加稳健地了解模型随时间的行为。

下面的示例在绘制每次运行的训练数据图和验证损失之前多次运行相同的实验。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
from pandas import DataFrame

# return training data
def get_train():
	seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((5, 1, 1))
	return X, y

# return validation data
def get_val():
	seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
	seq = array(seq)
	X, y = seq[:, 0], seq[:, 1]
	X = X.reshape((len(X), 1, 1))
	return X, y

# collect data across multiple repeats
train = DataFrame()
val = DataFrame()
for i in range(5):
	# define model
	model = Sequential()
	model.add(LSTM(10, input_shape=(1,1)))
	model.add(Dense(1, activation='linear'))
	# compile model
	model.compile(loss='mse', optimizer='adam')
	X,y = get_train()
	valX, valY = get_val()
	# fit model
	history = model.fit(X, y, epochs=300, validation_data=(valX, valY), shuffle=False)
	# story history
	train[str(i)] = history.history['loss']
	val[str(i)] = history.history['val_loss']

# plot train and validation loss across multiple runs
pyplot.plot(train, color='blue', label='train')
pyplot.plot(val, color='orange', label='validation')
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.show()

在得到的图中,我们可以看到欠拟合的总趋势在5次运行中保持不变,并且可能增加训练时期的数量。

诊断线图显示模型的多个运行

                                                                       诊断线图显示模型的多次运行

猜你喜欢

转载自blog.csdn.net/yangwohenmai1/article/details/84891478