邵洲作者

如何使用学习曲线来诊断你的LSTM模型的行为?(附代码)

LSTM是一种时间递归神经网络,适合于处理和预测时间序列中间隔和延迟相对较长的重要事件。在自然语言处理语言识别等一系列的应用上都取得了很好的效果。

《Long Short Term Memory Networks with Python》是澳大利亚机器学习专家Jason Brownlee的著作,里面详细介绍了LSTM模型的原理和使用。

该书总共分为十四个章节,具体如下:

第一章:什么是LSTMs?

第二章:怎么样训练LSTMs?

第三章:怎么样准备LSTMs的数据?

第四章:怎么样在Keras中开发LSTMs?

第五章:序列预测建模

第六章:如何开发一个Vanilla LSTM模型?

第七章:怎么样开发Stacked LSTMs?

第八章:开发CNN LSTM模型(本期内容)

第九章:开发Encoder-Decoder LSTMs

第十章:开发Bidirectional LSTMs

第十一章:开发生成LSTMs

第十二章:诊断和调试LSTMs(本期内容)

第十三章:怎么样用LSTMs做预测?(下周一发布)

第十四章:更新LSTMs模型

本文的作者对此书进行了翻译整理之后,分享给大家,本文是第十二期内容。

第一期内容为:一万字纯干货|机器学习博士手把手教你入门LSTM(附代码资料)

第二期内容为:干货推荐|如何基于时间的反向传播算法来训练LSTMs?

第三期内容为:干货推荐|如何准备用于LSTM模型的数据并进行序列预测?(附代码)

第四期内容为:机器学习博士带你入门|一文学会如何在Keras中开发LSTMs(附代码)

第五期内容为:初学者如何避免在序列预测问题中遇到的陷阱?

第六期内容为:如何开发和评估Vanilla LSTM模型?

第七期内容为:博士带你学LSTM|怎么样开发Stacked LSTMs?(附代码)

第八期内容为:博士带你学LSTM|手把手教你开发CNN LSTM模型,并应用在Keras中(附代码)

第九期内容为:博士带你学LSTM|开发Encoder-Decoder LSTM模型的简单教程(附代码)

第十期内容为:博士带你学LSTM|开发Bidirectional LSTM模型的简单教程(附代码)

第十一期内容为:博士带你学LSTM|怎么开发一个LSTM模型来生成形状?(附代码)

我们还将继续推出一系列的文章来介绍里面的详细内容,和大家一起来共同学习。

12.0 前言

12.0.1 课程目标

本课程的目标是学习怎么样调优LSTM参数。完成本课程之后,你将会学到:

  • 怎么样开发一个针对你的LSTM模型学习能力的健壮的评估;

  • 怎么样使用学习曲线来诊断你的LSTM模型的行为;

  • 怎么样调整LSTM模型的框架、结构和学习行为。

12.0.2 课程概览

本课程被分为5个部分,它们是:

  1. 评估LSTM模型;

  2. 诊断过拟合欠拟合

  3. 调优问题的框架;

  4. 调优模型结构;

  5. 调优学习行为。

让我们开始吧!

12.1 评估LSTM模型

在本章节中,你将发现用于开发对未知数据的LSTM模型的学习能力的文件估计的过程。

12.1.1 初学者的错误

你将模型拟合到你的训练数据并在测试数据集上进行评估,然后报告该学习能力。也许你用K折交叉验证来评估模型,然后报告模型的学习能力。这是初学者犯的错误。

看起来你做的是正确的事情,但是一个关键问题是你没有考虑过:深度学习模型是随机的。人工神经网络(如LSTM)在数据集上使用的随机性,例如在随机梯度下降期间每个训练周期的随机初始权重和数据的随机洗牌。这意味着,每次相同的模型适合于相同的数据,它可以给出不同的预测,进而具有不同的整体技能。

12.1.2 评估模型学习能力

我们没有所有可能的数据;如果我们做了,我们就不需要做预测。我们有一个有限的数据样本,从中我们需要发现最好的模型。

我通过将数据分割成两个部分,即对数据的第一部分进行模型或者特定模型配置,并使用拟合模型对其余部分进行预测,然后评估这些预测的技巧。这被称为训练-测试分割,我们使用这一技巧来估计模型在预测新数据时在实践中的表现。例如,这里有一些伪代码用于使用训练-测试分割来评估模型:

  1. train, test = random_split(data)  model = fit(train.X, train.y) predictions = model.predict(test.X) skill = compare(test.y, predictions)

表 12.1 评估模型技能的伪代码

如果你有很多的数据或者一个很慢的模型来训练,训练-测试分割是一个很好的方法,但是,由于数据中的随机性(模型的方差),模型的技能得分将是嘈杂的。这意味着相同的模型在不同数据上的拟合将会给不同模型技能分数。如果我们有资源,我们将会使用k折交叉验证。但是,在深度学习中使用大数据集合训练模型的速度慢,这通常是不可能的。

12.1.3 评估一个随机模型的技能

随机模型,如深度神经网络,添加一个额外的随机性来源。这种附加的随机性使得模型在学习时具有更高的灵活性,但可以使模型不太稳定(例如,当同一模型在同一数据上训练时会有不同的结果)。这是不同的模型方差,当不同的数据训练相同的模型时,给出不同的结果。

为了得到一个随机模型的技能的鲁棒估计,我们必须考虑这个额外的方差来源,我们必须控制它。一种稳健的方法是重复多次随机模型的评估实验。例如:

  1. scores = list()  for i in repeats: train, test = random_split(data) model = fit(train.X, train.y) predictions = model.predict(test.X) skill = compare(test.y, predictions) scores.append(skill) final_skill = mean(scores)

表 12.2 评估随机模型技能的伪代码

这是我推荐的用于评估深度学习模型的模型技能的伪代码

12.1.4 神经网络有多步稳定?

这取决于你的问题,取决于网络,以及它的配置。我建议进行敏感性分析来找出答案。在同一数据上对同一模型进行多次评估(30,100次或者数千次),只改变了随机数生成器的种子。然后回顾所产生的技能得分的平均值和标准差。标准差(平均得分与平均分数的距离)会让你知道你的模型有多不稳定。

12.1.5 多少次循环?

我建议至少30次,或许100次,甚至是上千次,限制的因素只有你的时间和电脑的资源(例如,平均技能的标准错误)。更严格地说,我将推荐一个实验,该实验着眼于估计模型技能对重复次数和标准误差计算的影响(平均估计性能与真实基础种群平均值的差异)。

12.1.6 模型估计之后

评估你的模型是达到目的的一种手段。它帮助你选择使用哪个模型以及使用哪些参数来配置它。一旦你选择了一个模型,你就必须初始化它。这包括将模型拟合在所有可能的数据上,并保存在以后用于预测新数据的位置上,我们不知道实际结果。在后面的章节中,我们将更详细地介绍模型最终的过程。

12.2 诊断欠拟合过拟合

在本章节中,你将会发现如何在训练期间使用LSTM模型的学习曲线图来诊断多拟合和欠拟合

12.2.1 在Keras中训练历史

你可以通过回顾模型的性能来了解模型的行为。通过调用fit()函数来训练LSTM模型。此函数返回一个名为history的变量,它包括损失的踪迹以及在编译模型期间指定的任何其他度量。这些分数记录在每一个周期的末尾。

... history = model.fit(...)

表 12.3 在拟合一个LSTM模型之后分配历史的例子

例如,如果你的模型被编译来优化对数损失(binary_crossentropy)并衡量每个周期的准确率,那么对数损失和准确率将被计算并记录在每个训练周期的历史轨迹中。每一个分数由调用fit()函数返回。默认情况下,当拟合模型被称为损失和准确率时,损失被称为acc。

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

表 12.4 在拟合LSTM模型之后打印历史的例子

Keras还允许你指定一个单独的验证数据集,同时也可以使用相同的损失和度量来评估模型。这可以通过在fit()函数上设置validation_split参数来实现,将训练数据的一部分用作验证数据集(特别是0到1之间的常量)。

... 

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

表 12.5 在训练数据子集计算验证损失的例子历史

这也可以通过设置验证数据参数和传递X和y数据集的元组来完成。

...  history = model.fit(X, Y, epochs=100, validation_data=(valX, valY))

表 12.6 在新数据集上包含验证损失的例子历史

在验证数据集上评估的度量使用相同的名称和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' ])

表 12.7 打印训练和验证损失和准确率的例子

12.2.2 诊断图

你的LSTM模型的训练历史可以用来诊断模型的行为。可以使用Matplotlib库绘制模型的性能。例如,你可以将训练损失和测试损失计分如下:

  1. from matplotlib import pyplot

  2. ... 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()

表 12.8 显示训练和验证损失和准确率的例子

创建和审阅这些图可以帮助你了解可能的新配置以尝试从模型中获得更好的性能。接下来,我们来看一些例子。我们将考虑在损失最小化的训练和验证集的模型技能。

12.2.3 欠拟合

欠拟合模型是一个在训练集上表现很好,但是在测试集上表现很差的模型。这可以从训练损失低于验证损失的图中诊断,验证损失有一个趋势,表明进一步的改进是可能的。下面提供了一个小型的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((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()

表 12.9 欠拟合LSTM显示训练和验证损失的例子

运行例子产生训练和验证损失的图,该图显示了一个欠拟合的模型。在这种情况下,表现将会通过增加训练的周期增加。

 图 12.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(LSTM1, 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()

表 12.10 一个欠拟合LSTM显示训练和验证损失的例子

运行这个例子显示了欠拟合模型供应不足的特征。在这种情况下,可以通过增加模型的容量来提高性能,例如隐藏层中的存储单元的数目或者隐藏层的数目。

 图 12.2 需要较大模型的欠拟合模型的诊断图

12.2.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()

表 12.11 刚好拟合显示训练和验证损失的例子

运行例子创建了一个显示训练和验证损失相遇的线图。理想情况下,我们希望看到模型性能,如果可能的话,虽然在很多的数据上这可能是不可能的挑战性问题。

 图 12.3 刚好拟合模型的诊断线图

12.2.5 过拟合

过拟合模型是在训练集上的性能是良好的,并持续改善,而验证集上的性能提高到一个点,然后开始下降。这可以从训练损失斜率下降,验证损失斜率下降,达到拐点,并开始再次上升的情节中被诊断出来。下面的例子演示了一个过拟合的LSTM模型。

  1. from keras.models import Sequential

  2. from keras.layers import Dense

  3. from keras.layers import LSTM

  4. from matplotlib import pyplot

  5. from numpy import array

  6. # return training data

  7. def get_train():

  8.     seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]

  9. seq = array(seq)

  10.     X, y = seq[:, 0], seq[:, 1]

  11. 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()

表 12.12 一个拟合LSTM显示训练和验证损失的例子

 图 12.4 显示过拟合的诊断线图

12.2.6 多次运行

LSTM是随机的,这意味着每一次运行的时候你都会得到一个不同的诊断图。重复多次的诊断运行是有用的(例如5,10或30)。然后,可以从每次运行中绘制出训练和验证轨迹,以得出随着时间推移模型的行为的更稳健的思想。下面的例子运行相同的实验多次,然后绘制每一次运行的训练轨迹和验证损失。

 图 12.5 多次运行模型的诊断线图

12.3 构建调参问题

本节概述了调整序列预测问题框架要考虑的最大杠杆作用的区域。

12.3.1 值缩放

评估不同数据值缩放方案对你的模型技能的影响。请记住在第一个隐藏层和/或输出层上更新激活函数,以处理作为输入或预测输出的值的范围。尝试的一些方案包括:

  • 规范化值;

  • 标准化值;

12.3.2 值编码

评估不同值编码对你模型技能的影响。标签序列,如字符或单词,通常是整数编码和one hot编码。假设这是对序列预测问题最熟练的方法。尝试一些编码方案包括:

  • 实值编码;

  • 整数编码

  • one hot编码。

12.3.3 稳定性

当使用一系列实际值,如时间序列时,考虑使序列平稳。

  • 删除趋势。如果该系列包含均值的方差(例如趋势),则可以使用差分。

  • 删除季节性。如果该系列包含周期性的周期(例如季节性),则可以使用季节性调整。

  • 删除方差。如果该系列包含一个递增或递减的方差,可可以使用日志或者Box-Cox变换。

12.3.4 输入序列长度

输入序列长度的选择困难 针对你的问题域,尽管有时它可能是你选择LSTM框架的一部分。评估使用不同输入序列长度对你模型技能的影响。记住,输入序列的长度也会影响在更新权重时用于估计误差梯度的时间的反向传播。它可以影响模型学习的速度和所学的知识。

12.3.5 序列模型类型

对于给定的序列预测问题有4个主要的模型序列类型:

  • One-to-one;

  • One-to-many;

  • Many-to-one;

  • Many-to-many。

Keras支持所有这些类型。使用每个序列模型类型来对问题进行构建,并评估模型技能,以帮助为你的问题选择框架。

12.4 模型结构调优

本节概述了调整LSTM模型结构时最大杠杆作用的一些方面。

12.4.1 结构

正如我们所看到的,有许多的LSTM体系结构可供选择。一些体系结构适用于某些序列预测问题,尽管大多数是足够的,以使它们适合于序列预测问题。测试你对结构实用性的假设。在你的序列预测问题中,评估本书中列出的每一个LSTM结构的技能(也许超出了)。

12.4.2 存储单元

对于给定的序列预测问题或者LSTM体系结构,我们不能知道存储单元的最佳数目是多少。必须在LSTM隐藏层中测试一组不同的存储单元,以查看哪些工作最有效。

  • 尝试网格搜索存储单元的数目为100s、10s或者更细;

  • 尝试事宜在研究论文中引用的单元数量;

  • 尝试随机搜索1到1000之间的单元格数量。

我经常看到像100或1000那样的原先存储单元。我想这些都是一时兴起选择的。下面是网格搜索的第一个隐藏LSTM层中存储单元1,5或10的数目的小例子,其中有少量的重复(5)。你可以用这个作为你自己试验的模板。

  1. from keras.models import Sequential

  2. from keras.layers import Dense

  3. from keras.layers import LSTM

  4. from matplotlib import pyplot

  5. from pandas import DataFrame

  6. from numpy import array

  7. # return training data

  8. def get_train():

  9.     seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]

  10.     seq = array(seq)

  11.     X, y = seq[:, 0], seq[:, 1]

  12. X = X.reshape((5, 1, 1))

  13. return X, y

  14. # return validation data

  15. 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]

  16. X = X.reshape((len(X), 1, 1))

  17.     return X, y

  18. # fit an LSTM model

  19. def fit_model(n_cells):

  20.     # define model

  21.     model = Sequential()

  22.     model.add(LSTM(n_cells, input_shape=(1,1)))

  23.     model.add(Dense(1, activation= 'linear' ))

  24.     # compile model

  25.     model.compile(loss= 'mse' , optimizer= 'adam' )

  26.     # fit model

  27.     X,y = get_train()

  28.     history = model.fit(X, y, epochs=500, shuffle=False, verbose=0)

  29. # evaluate model valX, valY = get_val() loss = model.evaluate(valX, valY, verbose=0) return loss # define scope of search params = [1, 5, 10] n_repeats = 5 # grid search parameter values scores = DataFrame() for value in params: # repeat each experiment multiple times loss_values = list() for i in range(n_repeats): loss = fit_model(value)

  30. loss_values.append(loss) print( '>%d/%d param=%f, loss=%f' % (i+1, n_repeats, value, loss)) # store results for this parameter scores[str(value)] = loss_values # summary statistics of results print(scores.describe()) # box and whisker plot of results scores.boxplot() pyplot.show()

表 12.14 网格搜索存储单元的数量的例子

运行例子打印搜索每次迭代的过程。每一个存储单元的结果的汇总统计在末尾显示。

  1. >1/5 param=1.000000, loss=0.047335

    >2/5 param=1.000000, loss=0.146885

  2. >3/5 param=1.000000, loss=0.104599

  3. >4/5 param=1.000000, loss=0.345472

  4. >5/5 param=1.000000, loss=0.115182

  5. >1/5 param=5.000000, loss=0.020112

  6. >2/5 param=5.000000, loss=0.084113

  7. >3/5 param=5.000000, loss=0.042612

  8. >4/5 param=5.000000, loss=0.070742

  9. >5/5 param=5.000000, loss=0.038660

  10. >1/5 param=10.000000, loss=0.040568

  11. >2/5 param=10.000000, loss=0.009704

  12. >3/5 param=10.000000, loss=0.064492

  13. >4/5 param=10.000000, loss=0.017800

  14. >5/5 param=10.000000, loss=0.012813

  15. 1 5 10

    count 5.000000 5.000000 5.000000 mean 0.151895 0.051248 0.029075

  16. std 0.114033 0.025801 0.023202 min 0.047335 0.020112 0.009704 25% 0.104599 0.038660 0.012813 50% 0.115182 0.042612 0.017800 75% 0.146885 0.070742 0.040568 max 0.345472 0.084113 0.064492

表 12.15 网格搜索存储单元的数量输出的例子

最后结果的箱线图被创建来比较每种不同的模型配置的模型技能分布。

 图 12.6 调整存储单元结果的箱线图

12.4.3 隐藏层

与存储单元的数目一样,对于给定的序列预测问题或LSTM体系结构,我们不能知道LSTM隐藏层的最佳数量。当你有很多数据时,越深越好。

  • 尝试一起网格搜索层数和存储单元;

  • 尝试使用堆叠LSTM层在研究论文中引用的模式;

  • 尝试一起随机搜索层数和存储单元。

创建深度卷积神经网络(CNNs)是有模式的。我没有看见过任何复杂的模式,LSTM超出encoder-decoder模式。我认为这是一个有待探索的大问题。你能设计出总体上工作良好的stacked LSTM吗?

12.4.4 权重初始化

Keras的LSTM层默认使用 glorot_uniform做权重的初始化。总体来说,这个权重初始化运行得很好,但是我已经使用LSTM的正常类型权重初始化取得了很大的成功。评估不同的权重初始化方案对您的模型技能的影响。Keras提供了一个很好的权重初始化列表供您尝试。至少,比较这始终方法的技巧:

  • random_uniform

  • random_normal

  • glorot_uniform

  • glorot_normal

12.4.5 激活函数

激活函数(技术上是传递神经元的加权激活时的传递函数)通常由输入层或输出层的框架和尺度来固定。例如,LSTM使用sigmoid激活函数作为输入并且因此输入通常在0-1的刻度中。序列预测问题的分类或者回归性质决定了在输出层中使用激活函数的类型。挑战LSTM层中默认的sigmoid激活函数。也许在重新调整输入值的同时,尝试使用其他的方法。例如,尝试:

  • sigmoid

  • tanh

  • relu

此外,挑战在一个stacked LSTM中所有的LSTM层是否需要使用相同的激活函数。在实践中,我很少看到一个模型比使用sigmoid更好,但是这个假设应该需要得到证实。

12.5 调优学习行为

本章节概述了调整LSTM模型学习行为时的最大杠杆作用的一些方面。

12.5.1 优化算法

梯度下降的一个很好的默认实现是用Adam算法。这是因为它结合AdaGrad和RMSProp方法的最佳属性自动为模型中的每个参数权重)使用自定义学习率。此外,在Keras中使用每个配置参数的最佳实践初始值实现Adam。

然而,挑战Adam是你的模型的正确的梯度下降算法。用不同的梯度下降算法评估模型的性能。现代算法的一些思想包括:

  • Adam

  • RMSprop

  • Adagrad

12.5.2 学习率

学习率控制权重更新多少,作为在每个批次结束时响应估计的梯度。这会对模型的学习率和模型之间的权衡产生很大的影响。考虑使用经典随机梯度下降(SGD)优化器,并探索不同的学习率动量值,你可以评估不同的学习率的制度。

  • 网格搜索学习速率值(例如0.1, 0.001、0.0001);

  • 学习速率衰减的周期(epoch)的实验(例如通过回调);

  • 训练模型更新与训练的学习率越来越小的实验。

学习率和周期(通过训练样本的传递次数)紧密耦合。一般来说,学习率(例如0.0001)越小,就需要更多的训练周期。这是一个线性关系,所以反过来也是正确的,在更大的学习率需要更少的周期(例如0.1)。

12.5.3 批次大小

批次大小是模型权重更新之间的样本数。一个磨的默认批次大小是32个样本。

批次大小典型的选择是从1到几千,例如批次大小为32是一个好的默认值,利用矩阵成绩加速到矩阵向量乘积的值大于10。

— Practical Recommendations For Gradient-based Training Of Deep Architectures, 2012.

序列预测问题的数据量和帧的大小可能取决于批次大小的选择。然而,挑战你的最佳猜想并尝试一些替代的配置。

  • 随机梯度下降批次大小为1;

  • 批次大小为n,其中n是批次梯度下降的样本数;

  • 网格搜索批大小为2的平方,从2到256不等。

较大的批次大小通吃会导致模型更快收敛,但可能会导致一个不太理想的权重集。批次大小为1(随机梯度下降)更新后,每个样本往往导致非常嘈杂的学习过程。下面是网格搜索的一个小例子,该批次大小为1、2和3,具有少量的重复(5)。你可以用这个例子作为自己试验的模板。

  1. from keras.models import Sequential

    from keras.layers import Dense

  2. from keras.layers import LSTM

  3. from matplotlib import pyplot

  4. from pandas import DataFrame

  5. from numpy import array

  6. # return training data

  7. def get_train():

  8. 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 # fit an LSTM model def fit_model(n_batch): # 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() history = model.fit(X, y, epochs=500, shuffle=False, verbose=0, batch_size=n_batch) # evaluate model valX, valY = get_val() loss = model.evaluate(valX, valY, verbose=0) return loss # define scope of search params = [1, 2, 3] n_repeats = 5 # grid search parameter values scores = DataFrame() for value in params: # repeat each experiment multiple times loss_values = list() for i in range(n_repeats): loss = fit_model(value) loss_values.append(loss) print( '>%d/%d param=%f, loss=%f' % (i+1, n_repeats, value, loss)) # store results for this parameter scores[str(value)] = loss_values # summary statistics of results print(scores.describe()) # box and whisker plot of results

  9. scores.boxplot() pyplot.show()

表 12.16 网格搜索批次大小的例子

运行这个例子打印搜索每次迭代的进度。最后对每个配置结果进行汇总统计。

  1. >1/5 param=1.000000, loss=0.000524 >2/5 param=1.000000, loss=0.003064 >3/5 param=1.000000, loss=0.000918 >4/5 param=1.000000, loss=0.001103 >5/5 param=1.000000, loss=0.002519 >1/5 param=2.000000, loss=0.000851 >2/5 param=2.000000, loss=0.000069 >3/5 param=2.000000, loss=0.000339 >4/5 param=2.000000, loss=0.000048 >5/5 param=2.000000, loss=0.001156 >1/5 param=3.000000, loss=0.013446 >2/5 param=3.000000, loss=0.001138 >3/5 param=3.000000, loss=0.006436 >4/5 param=3.000000, loss=0.002005 >5/5 param=3.000000, loss=0.011653 1 2 3 count 5.000000 5.000000 5.000000 mean 0.001626 0.000493 0.006936 std 0.001102 0.000492 0.005541 min 0.000524 0.000048 0.001138 25% 0.000918 0.000069 0.002005 50% 0.001103 0.000339 0.006436 75% 0.002519 0.000851 0.011653 max 0.003064 0.001156 0.013446

表 12.17 网格搜索批次大小输出的例子

最后结果的箱线图创建来用于比较每个不同配置的模型技能的分布。

 图 12.7 调整批次大小结果的箱线图

12.5.4 正则化

在某些序列预测问题上,LSTM可以快速收敛,甚至过拟合。为了解决这个问题,可以使用正则化方法。Dropout在训练过程随机跳过神经元,迫使该层中的其他神经元来收拾残局。它简单有效。从dropout开始。Dropout率在0(不dropout)和1(完全dropout)之间,可以在通过两个不同的参数在LSTM层上设置:

  • dropout。dropout应用于输入连接。

  • recurrent_dropout。dropout应用于循环连接。

例如:

  1. model.add(LSTM(..., dropout=0.4))

表 12.18 用输入连接dropout添加一层的例子

一些需要去尝试的例子包括:

  • 网格搜索不同的dropout百分比;

  • 在输入、隐藏和输出层中进行dropout实验。

LSTM还支持其他形式的正则化,如权重规则化,施加压力以减少网络权重的大小。同样,这些参数可以在LSTM层上设置:

  • 偏置正则化:对偏置的正则化

  • 正则化:对输入权重正则化

  • 循环正则化:对循环权重正则化

你可以使用正则化类,如L1、L2或者L1L2正则化,而不是dropout的百分比。我建议使用L1L2,使用0和1之间的值,也允许模拟T1和T2方法。例如,你可以试试:

  • L1L2(0.0, 0.0),例如,基准线或者无正则化

  • L1L2(0.01, 0.0),例如,L1;

  • L1L2(0.0, 0.01),例如,L2;

  • L1L2(0.01, 0.01),例如,L1L2也称为弹性网。

  1. model.add(LSTM(..., kernel_regularizer=L1L2(0.01, 0.01)))

表 12.19 用输入权重正则化添加一层的例子

在实践中,我们发现输入连接上的dropout和输入权重正则化,从而导致更好的执行模型。

12.5.5 早停

训练周期的数量调优会非常的耗时间。另外一种方法是使大量的训练周期(epoch)称为可能。然后设置一些东西来检查模型在训练和验证数据集上的性能,如果模型看起来开始过度学习,停止训练。因此,早期停止是一种正则化,以抑制过度拟合。

你可以在Keras的早期停止实验中用一个EarlyStopping回调。它需要你指定一些参数配置,例如用于监视的度量(例如val-损失),在所观察到的次数上没有到的监视度量的改进(例如100)。在对模型进行训练时,将回调列表提供给fit()函数。例如:

from keras.callbacks import EarlyStopping

es = EarlyStopping(monitor= val_loss , min_delta=100) model.fit(..., callbacks=[es])

表 12.20 使用EarlyStopping回调的例子

12.6 扩展阅读

本章节提供了一些用于扩展阅读的资源:

12.6.1 书籍

  • Empirical Methods for Artificial Intelligence, 1995.

12.6.2 论文

  • Practical recommendations for gradient-based training of deep architectures, 2012.

  • Recurrent Neural Network Regularization, 2014.

12.6.3 APIs

  • Sequential Model API in Keras.

  • LSTM Layer API in Keras.

  • Weight Initializers API in Keras.

  • Optimized API in Keras.

  • Callbacks API in Keras.

12.7 总结

本课程中, 你学习到了怎么样对LSTM的参数调优。特别地,你学习到了:

  • 怎么样开发一个针对你的LSTM模型学习能力的健壮的评估;

  • 怎么样使用学习曲线来诊断你的LSTM模型的行为;

  • 怎么样调整LSTM模型的框架、结构和学习行为。

在下面的课程中,你将会学习到怎么样完成LSTM模型,并使用它来对数据进行预测。

作者介绍:邵洲,在读博士。研究兴趣:数据挖掘、学者迁徙研究。

AMiner学术头条
AMiner学术头条

AMiner平台由清华大学计算机系研发,拥有我国完全自主知识产权。系统2006年上线,吸引了全球220个国家/地区800多万独立IP访问,数据下载量230万次,年度访问量1000万,成为学术搜索和社会网络挖掘研究的重要数据和实验平台。

https://www.aminer.cn/
专栏二维码
工程过拟合欠拟合神经网络LSTM
4
相关数据
来也机构

「来也」是国内领先的人工智能交互平台,由常春藤盟校(Ivy League)归国博士和MBA团队发起,核心技术涵盖自然语言处理(NLP)、多轮对话控制和个性化推荐系统等。公司已获得数十项专利和国家高新技术企业认证。 来也的愿景是通过AI赋能,让每个人拥有助理。C 端产品小来是智能化的在线助理,通过业内创新的AI+Hi模式,提供日程、打车、咖啡、差旅和个性化查询等三十余项技能(覆盖400w用户和数十万服务者),让用户用自然语言发起需求并得到高效的满足。B端品牌吾来输出知识型的交互机器人和智能客户沟通系统,帮助各领域企业客户打造行业助理。目前已经在母婴,商旅,金融和汽车等行业的标杆企业实现商业化落地。

https://www.laiye.com/
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

网格搜索技术

网格搜索是一项模型超参数优化技术,常用于优化三个或者更少数量的超参数,本质是一种穷举法。对于每个超参数,使用者选择一个较小的有限集去探索。然后,这些超参数笛卡尔乘积得到若干组超参数。网格搜索使用每组超参数训练模型,挑选验证集误差最小的超参数作为最好的超参数。

激活函数技术

在 计算网络中, 一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。标准的计算机芯片电路可以看作是根据输入得到"开"(1)或"关"(0)输出的数字网络激活函数。这与神经网络中的线性感知机的行为类似。 一种函数(例如 ReLU 或 S 型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

欠拟合技术

使用太少参数,以致于不能很好的拟合数据,称为拟合不足(欠拟合)现象

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

Dropout技术

神经网络训练中防止过拟合的一种技术

基准技术

一种简单的模型或启发法,用作比较模型效果时的参考点。基准有助于模型开发者针对特定问题量化最低预期效果。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

学习曲线技术

在机器学习领域,学习曲线通常是表现学习准确率随着训练次数/时长/数据量的增长而变化的曲线

收敛技术

在数学,计算机科学和逻辑学中,收敛指的是不同的变换序列在有限的时间内达到一个结论(变换终止),并且得出的结论是独立于达到它的路径(他们是融合的)。 通俗来说,收敛通常是指在训练期间达到的一种状态,即经过一定次数的迭代之后,训练损失和验证损失在每次迭代中的变化都非常小或根本没有变化。也就是说,如果采用当前数据进行额外的训练将无法改进模型,模型即达到收敛状态。在深度学习中,损失值有时会在最终下降之前的多次迭代中保持不变或几乎保持不变,暂时形成收敛的假象。

学习率技术

在使用不同优化器(例如随机梯度下降,Adam)神经网络相关训练中,学习速率作为一个超参数控制了权重更新的幅度,以及训练的速度和精度。学习速率太大容易导致目标(代价)函数波动较大从而难以找到最优,而弱学习速率设置太小,则会导致收敛过慢耗时太长

时间递归神经网络技术

时间递归神经网络 (aka.循环神经网络, RNN) 是一类擅长处理序列数据的神经网络,其单元连接形成一个有向环。一般人工神经网络(ANN)由多层神经元组成,典型的连接方式是在前馈神经网络中,仅存在层与层之间的互相连接,而同层神经元之间没有连接。RNN在此基础上结合了隐藏层的循环连接,从而能从序列或时序数据中学习特征和长期依赖关系。RNN隐藏层的每一单独计算单元对应了数据中某个时间节点的状态,它可以是简单神经元、神经元层或各式的门控系统。 每一单元通过参数共享的层间顺序连接,并随着数据序列传播。这一特性使得RNN中每一单元的状态都取决于它的过去状态,从而具有类似“记忆”的功能,可以储存并处理长时期的数据信号。 大多数RNN能处理可变长度的序列,理论上也可以建模任何动态系统。

超参数技术

在机器学习中,超参数是在学习过程开始之前设置其值的参数。 相反,其他参数的值是通过训练得出的。 不同的模型训练算法需要不同的超参数,一些简单的算法(如普通最小二乘回归)不需要。 给定这些超参数,训练算法从数据中学习参数。相同种类的机器学习模型可能需要不同的超参数来适应不同的数据模式,并且必须对其进行调整以便模型能够最优地解决机器学习问题。 在实际应用中一般需要对超参数进行优化,以找到一个超参数元组(tuple),由这些超参数元组形成一个最优化模型,该模型可以将在给定的独立数据上预定义的损失函数最小化。

伪代码技术

伪代码,又称为虚拟代码,是高层次描述算法的一种方法。它不是一种现实存在的编程语言;它可能综合使用多种编程语言的语法、保留字,甚至会用到自然语言。 它以编程语言的书写形式指明算法的职能。相比于程序语言它更类似自然语言。它是半形式化、不标准的语言。

验证集技术

验证数据集是用于调整分类器超参数(即模型结构)的一组数据集,它有时也被称为开发集(dev set)。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

反向传播算法技术

反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。该方法计算对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。 在神经网络上执行梯度下降法的主要算法。该算法会先按前向传播方式计算(并缓存)每个节点的输出值,然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。

数据挖掘技术

数据挖掘(英语:data mining)是一个跨学科的计算机科学分支 它是用人工智能、机器学习、统计学和数据库的交叉方法在相對較大型的数据集中发现模式的计算过程。 数据挖掘过程的总体目标是从一个数据集中提取信息,并将其转换成可理解的结构,以进一步使用。

梯度下降技术

梯度下降是用于查找函数最小值的一阶迭代优化算法。 要使用梯度下降找到函数的局部最小值,可以采用与当前点的函数梯度(或近似梯度)的负值成比例的步骤。 如果采取的步骤与梯度的正值成比例,则接近该函数的局部最大值,被称为梯度上升。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

随机梯度下降技术

梯度下降(Gradient Descent)是遵循成本函数的梯度来最小化一个函数的过程。这个过程涉及到对成本形式以及其衍生形式的认知,使得我们可以从已知的给定点朝既定方向移动。比如向下朝最小值移动。 在机器学习中,我们可以利用随机梯度下降的方法来最小化训练模型中的误差,即每次迭代时完成一次评估和更新。 这种优化算法的工作原理是模型每看到一个训练实例,就对其作出预测,并重复迭代该过程到一定的次数。这个流程可以用于找出能导致训练数据最小误差的模型的系数。

大数据技术技术

大数据,又称为巨量资料,指的是传统数据处理应用软件不足以处理它们的大或复杂的数据集的术语。

规范化技术

规范化:将属性数据按比例缩放,使之落入一个小的特定区间,如-1.0 到1.0 或0.0 到1.0。 通过将属性数据按比例缩放,使之落入一个小的特定区间,如0.0到1.0,对属性规范化。对于距离度量分类算法,如涉及神经网络或诸如最临近分类和聚类的分类算法,规范化特别有用。如果使用神经网络后向传播算法进行分类挖掘,对于训练样本属性输入值规范化将有助于加快学习阶段的速度。对于基于距离的方法,规范化可以帮助防止具有较大初始值域的属性与具有较小初始值域的属相相比,权重过大。有许多数据规范化的方法,包括最小-最大规范化、z-score规范化和按小数定标规范化。

过拟合技术

过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是分类器设计中的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价。

敏感性分析技术

敏感性分析是研究数学模型或系统的输出的不确定性(数值或其他)如何能够分配到输入中不同的不确定性来源

神经元技术

(人工)神经元是一个类比于生物神经元的数学计算模型,是神经网络的基本组成单元。 对于生物神经网络,每个神经元与其他神经元相连,当它“兴奋”时会向相连的神经元发送化学物质,从而改变这些神经元的电位;神经元的“兴奋”由其电位决定,当它的电位超过一个“阈值”(threshold)便会被激活,亦即“兴奋”。 目前最常见的神经元模型是基于1943年 Warren McCulloch 和 Walter Pitts提出的“M-P 神经元模型”。 在这个模型中,神经元通过带权重的连接接处理来自n个其他神经元的输入信号,其总输入值将与神经元的阈值进行比较,最后通过“激活函数”(activation function)产生神经元的输出。

语言识别技术

在自然语言处理中,语言识别或语言猜测是确定给定内容所使用的自然语言的问题。针对该问题的计算方法被视为文本分类的特例,并用各种统计方法解决。

正则化技术

当模型的复杂度增大时,训练误差会逐渐减小并趋向于0;而测试误差会先减小,达到最小值后又增大。当选择的模型复杂度过大时,过拟合现象就会发生。这样,在学习时就要防止过拟合。进行最优模型的选择,即选择复杂度适当的模型,以达到使测试误差最小的学习目的。

随机搜索技术

自然语言处理技术

自然语言处理(英语:natural language processing,缩写作 NLP)是人工智能和语言学领域的分支学科。此领域探讨如何处理及运用自然语言;自然语言认知则是指让电脑“懂”人类的语言。自然语言生成系统把计算机数据转化为自然语言。自然语言理解系统把自然语言转化为计算机程序更易于处理的形式。

动量技术

优化器的一种,是模拟物理里动量的概念,其在相关方向可以加速SGD,抑制振荡,从而加快收敛

交叉验证技术

交叉验证,有时亦称循环估计, 是一种统计学上将数据样本切割成较小子集的实用方法。于是可以先在一个子集上做分析, 而其它子集则用来做后续对此分析的确认及验证。 一开始的子集被称为训练集。而其它的子集则被称为验证集或测试集。交叉验证的目标是定义一个数据集到“测试”的模型在训练阶段,以便减少像过拟合的问题,得到该模型将如何衍生到一个独立的数据集的提示。

批次技术

模型训练的一次迭代(即一次梯度更新)中使用的样本集。

堆叠技术

堆叠泛化是一种用于最小化一个或多个泛化器的泛化误差率的方法。它通过推导泛化器相对于所提供的学习集的偏差来发挥其作用。这个推导的过程包括:在第二层中将第一层的原始泛化器对部分学习集的猜测进行泛化,以及尝试对学习集的剩余部分进行猜测,并且输出正确的结果。当与多个泛化器一起使用时,堆叠泛化可以被看作是一个交叉验证的复杂版本,利用比交叉验证更为复杂的策略来组合各个泛化器。当与单个泛化器一起使用时,堆叠泛化是一种用于估计(然后纠正)泛化器的错误的方法,该泛化器已经在特定学习集上进行了训练并被询问了特定问题。

深度神经网络技术

深度神经网络(DNN)是深度学习的一种框架,它是一种具备至少一个隐层的神经网络。与浅层神经网络类似,深度神经网络也能够为复杂非线性系统提供建模,但多出的层次为模型提供了更高的抽象层次,因而提高了模型的能力。

优化器技术

优化器基类提供了计算梯度loss的方法,并可以将梯度应用于变量。优化器里包含了实现了经典的优化算法,如梯度下降和Adagrad。 优化器是提供了一个可以使用各种优化算法的接口,可以让用户直接调用一些经典的优化算法,如梯度下降法等等。优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。用户基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer(tensorflow下的优化器包)等等这些算法。

推荐文章
暂无评论
暂无评论~