原文链接:http://tecdat.cn/?p=23616
在这篇文章中,咱们将回顾三种进步循环神经网络的性能和泛化能力的高级办法。咱们将在一个温度预测问题上演示这三个概念,咱们应用来自装置在建筑物屋顶的传感器的数据点的工夫序列。
概述
装置在建筑物屋顶的传感器的数据点的工夫序列,如温度、气压和湿度,你用这些数据点来预测最初一个数据点之后 24 小时的温度。这是一个相当具备挑战性的问题,它体现了在解决工夫序列时遇到的许多常见艰难。
咱们将介绍以下办法。
- 递归剔除 – 这是一种特定的、内置的形式,应用剔除来反抗递归层中的适度拟合。
- 重叠递归层 – 这减少了网络的示意能力(以较高的计算负荷为代价)。
- 双向递归层 – 这些层以不同的形式向递归网络出现雷同的信息,进步了准确性并缓解了忘记问题。
温度预测的问题
到目前为止,咱们所波及的序列数据只有文本数据,如 IMDB 数据集和路透社数据集。然而,序列数据在许多问题中都能找到,而不仅仅是语言解决。在本节的所有例子中,你将剖析一个天气工夫序列数据集,该数据集来自生物地球化学研究所的气象站记录。
在这个数据集中,14 个不同的量(如气温、大气压力、湿度、风向等)每 10 分钟被记录一次,历时数年。原始数据能够追溯到 2003 年,但这个例子仅限于 2009-2016 年的数据。这个数据集是学习解决数字工夫序列的完满抉择。你将用它来建设一个模型,把最近的一些数据(几天的数据点)作为输出,预测将来 24 小时的空气温度。
下载并解压数据如下。
``````
unzip("~/Downloads/climate.csv.zip",)
咱们来看看这些数据。
``````
glimpse(data)
这里是温度(摄氏度)随工夫变动的曲线图。在这个图上,你能够分明地看到温度的年度周期性。
``````
plot(data, geom_line)
上面是前 10 天的温度数据图(见图 6.15)。因为数据是每 10 分钟记录一次,所以每天失去 144 个数据点。
plot(data\[,\], line()
在这个图上,你能够看到每天的周期性,特地是在过来的 4 天里很显著。还要留神的是,这 10 天的工夫来自凛冽的夏季。
如果你依据过来几个月的数据来预测下个月的平均温度,问题就很容易了,因为数据具备牢靠的年尺度的周期性。看一下过来的数据
筹备数据
问题的确切表述如下:给定的数据最远可追溯到回溯时间段(一个时间段是 10 分钟),并且每步时间段取样,你将应用以下参数值。
lookback = 1440
— 察看后果将回到 10 天前。steps = 6
— 察看后果将以每小时一个数据点的速度进行采样。delay = 144
—指标是将来的 24 小时。
筹备工作。
- 将数据预处理成神经网络能够摄入的格局。这很容易:数据曾经是数值化的,所以你不须要做任何矢量化。然而,数据中的每个工夫序列都在不同的量纲上(例如,温度通常在 -20 和 +30 之间,但大气压力,以 mbar 为单位,大概是 1000)。你将独立地对每个工夫序列进行归一化解决,使它们都在一个相似的量纲上取小值。
- 编写一个生成器函数,获取以后的浮点数据数组,并产生最近的数据批,以及将来的指标温度。因为数据集中的样本是高度冗余的(样本 N 和样本 N + 1 将有大部分独特的工夫步长),明确调配每个样本是不合理的。取而代之的是,你将应用原始数据生成样本。
了解生成器函数
生成器函数是一种非凡类型的函数,你重复调用它来获取一连串的值。通常状况下,生成器须要放弃外部状态,所以它们通常是通过调用另一个又一个返回生成器函数的函数来结构的(返回生成器的函数的环境随后被用来跟踪状态)。
例如,上面产生一个有限的数字序列。
generator <- function(start) {
value <- start - 1
value <<- value + 1
value
}
gen <- generator(10)
\[1\] 10
gen()
\[1\] 11
生成器的以后状态是定义在函数之外的值变量。留神,超级赋值(<<->)是用来从函数外部更新这个状态的。
生成器函数能够通过返回值 NULL 来示意实现。然而,传递给 Keras 训练方法(例如生成器函数应该总是有限地返回值(对生成器函数的调用次数由 epochs 和 psych\_per\_epoch 参数管制)。
首先,你要把咱们之前读到的 R 数据帧转换为浮点值矩阵。
data <- data.matrix(data\[,-1\])
而后,你将对数据进行预处理,减去每个工夫序列的平均值并除以标准差。你将应用前 20 万个时间段作为训练数据,所以只对这部分数据计算均值和标准差进行归一化。
train_data <- data\[1:200000,\]
data <- scale(data, center = mean, scale = std)
上面是你要应用的数据生成器的代码。它产生一个列表(samples, targets),其中 samples 是一批输出数据,target 是相应的指标温度阵列。它须要以下参数。
data - 原始的浮点数据数组,你对其进行了标准化解决
lookback
— 输出的数据应该回到多少个时间段。delay
—指标应该在将来多少个时间段.min_index
和max_index
—数据数组中的索引,用来限定从哪个时间段提取。这对于保留一部分数据用于验证,另一部分用于测试很有用.shuffle
— 是否对样本进行随机打乱或按工夫程序抽取.batch_size
—每批样本的数量.step
— 你对数据进行采样的周期,以工夫为单位。你将设置为 6,以便每小时绘制一个数据点.
i 变量蕴含跟踪下一个数据窗口返回的状态,所以它应用超级赋值进行更新(例如,i <<- i + length(rows))。
当初,让咱们应用生成器函数来实例化三个生成器:一个用于训练,一个用于验证,还有一个用于测试。每个生成器将查看原始数据的不同时间段:训练生成器查看前 20 万个时间段,验证生成器查看随后的 10 万个时间段,而测试生成器查看残余的时间段。
# 为了遍历整个验证集,要从 val_gen 中抽取多少步
val\_steps <- (300000 - 200001 - lookback) / batch\_size
# 为了遍历整个测试集,要从 test_gen 中抽取多少步
test\_steps <- (nrow(data) - 300001 - lookback) / batch\_size
常识性、非机器学习的基准模型
在你开始应用黑盒深度学习模型来解决温度预测问题之前,让咱们尝试一个简略的、常识性的办法。这将作为一种理智的查看,它将建设一个基准模型,以证实更先进的机器学习模型的有用性。当你在解决一个新的问题时,这种常识性的基线可能是有用的,因为目前还没有已知的解决方案。一个典型的例子是不均衡的分类工作,其中一些类别比其余类别要常见得多。如果你的数据集蕴含 90% 的 A 类实例和 10% 的 B 类实例,那么分类工作的一个常识性办法就是在遇到新样本时总是预测 “A”。这样的分类器总体上有 90% 的准确度,因而任何基于学习的办法都应该超过这个 90% 的分数,以证实其有用性。
在这种状况下,能够平安地假如温度工夫序列是间断的(今天的温度可能与明天的温度靠近),以及具备每日周期性的。因而,一个常识性的办法是始终预测 24 小时后的温度将与当初的温度相等。让咱们应用均匀绝对误差(MAE)指标来评估这种办法。
``````
mean(abs(preds - targets))
上面是评估循环。
``````
for (step in 1:val_steps) {c(samples, targets) %<-% val_gen()
preds <- samples\[,dim(samples)\[\[2\]\],2\]
mae <- mean(abs(preds - targets))
batch\_maes <- c(batch\_maes, mae)
}
这得出的 MAE 为 0.29。因为温度数据曾经被归一化,以 0 为核心,标准差为 1。它转化为均匀绝对误差为 0.29 x temperature_std 摄氏度:2.57˚C。
这是一个相当大的均匀绝对误差。当初利用深度学习来做得更好。
根本的机器学习办法
在尝试机器学习办法之前,建设一个常识性的基线是很有用的,同样,在钻研简单和计算低廉的模型(如 RNN)之前,尝试简略、便宜的机器学习模型(如小型、密集连贯的网络)也是很有用的。这是确保你在这个问题上投入的任何进一步的复杂性都是非法的,并带来真正的益处的最好办法。
上面的列表显示了一个全连贯模型,它从扁平化的数据开始,而后通过两个密集层运行。留神最初一个密集层上没有激活函数,这对于回归问题来说是典型的。你应用 MAE 作为损失函数。因为你用完全相同的数据和完全相同的指标来评估你的常识性办法,所以后果将是间接可比的。
``````
model %>% compile(optimizer = optimizer_rmsprop(),
loss = "mae"
)
验证和训练的损失曲线。
一些验证损失靠近于无学习基线,但并不牢靠。这就阐明了首先要有这个基准的益处:事实证明,要超过它并不容易。你的常识蕴含了很多机器学习模型无奈取得的贵重信息。
你可能会想,如果存在一个简略的、体现良好的模型来从数据到指标(常识基准),为什么你正在训练的模型没有发现它并在此基础上进行改良?因为这个简略的解决方案并不是你的训练设置所要寻找的。你在其中寻找解决方案的模型空间 – 也就是你的假如空间 – 是所有可能的两层网络的空间,其配置由你定义。这些网络曾经相当简单了。当你用一个简单的模型空间寻找解决方案时,简略的、体现良好的基线可能是不可学习的,即便它在技术上是假如空间的一部分。这是机器学习的一个相当重要的限度:除非学习算法被硬编码为寻找一种特定的简略模型,否则参数学习有时可能无奈找到一个简略问题的简略解决方案。
第一个递归基准模型
第一个全连贯办法做得不好,但这并不意味着机器学习不适用于这个问题。之前的办法首先对工夫序列进行了扁平化解决,将工夫的概念从输出数据中移除。相同,让咱们把数据看成是:一个序列,其中因果关系和程序很重要。你将尝试一个循环序列解决模型 – 它应该是最适宜这种序列数据的,正是因为它利用了数据点的工夫程序,与第一种办法不同。
你将应用 Chung 等人在 2014 年开发的 GRU 层,而不是上一节中介绍的 LSTM 层。门控递归单元(GRU)层的工作原理与 LSTM 雷同,但它们有些精简,因而运行老本更低(只管它们可能没有 LSTM 那么多的示意能力)。在机器学习中,这种计算能力和体现能力之间的衡量随处可见。
layer\_gru(units = 32, input\_shape = list(NULL, dim(data)\[\[-1\]\])) %>%
layer_dense(units = 1)
后果绘制如下。好多了,你能够大大超越常识性的基准模型,证实了机器学习的价值,以及在这种类型的工作上,递归网络比序列平坦的密集网络更有劣势。
交互显示训练过程中的模型损失:
新的验证 MAE 为~0.265(在你开始显著过拟合之前),转化为去标准化后的均匀绝对误差为 2.35˚C。与最后的 2.57℃的误差相比,这是一个提高,但你可能仍有一点改良的余地。
应用递归抛弃 dropout 来反抗过拟合
从训练和验证曲线中能够看出,该模型正在适度拟合:训练和验证损失在几个 epochs 之后开始呈现显著的一致。你曾经相熟了反抗这种景象的经典技术:dropout,它随机地将一个层的输出单元清零,以突破该层所接触的训练数据中的偶尔相关性。
Yarin Gal 应用 Keras 进行钻研,并帮忙将这一机制间接构建到 Keras 的递归层中。Keras 中的每个递归层都有两个与 dropout 相干的参数:dropout,一个指定该层输出单元的 dropout 率的浮点数,以及 recurrent\_dropout,指定递归单元的 dropout 率。让咱们在 layer\_gru 中退出 dropout 和 recurrent dropout,看看这样做对过拟合有什么影响。因为用 dropout 进行正则化的网络总是须要更长的工夫来齐全收敛,所以你将训练网络两倍的 epochs。
layer_gru(dropout = 0.2))
上面的图显示了后果。你在前 20 个 epochs 中不再适度拟合。然而,只管你有更稳固的评估分数,你的最佳分数并没有比以前低很多。
重叠递归层
因为你不再适度拟合,但仿佛遇到了性能瓶颈,你应该思考减少网络的容量。回顾一下通用机器学习工作流程的形容:一般来说,减少网络的容量是个好主见,直到过拟合成为次要阻碍(假如你曾经采取了根本措施来加重过拟合,比方应用 dropout)。
减少网络容量通常是通过减少层中的单元数量或增加更多的层来实现的。递归层重叠是建设更弱小的递归网络的经典办法:例如,目前为谷歌翻译算法提供能源的是七个大型 LSTM 层的重叠。
为了在 Keras 中把递归层重叠起来,所有的中间层都应该返回它们的残缺输入序列(一个三维张量),而不是它们在最初一个工夫步的输入。这能够通过指定 return_sequences = TRUE 来实现。
layer_gru(
return_sequences = TRUE,
input_shape = list(NULL, dim(data)\[\[-1\]\])) %>%
下图显示了后果。你能够看到,增加的层的确改善了一些后果,只管并不显著。你能够得出两个论断。
- 因为你的过拟合状况依然不是很重大,所以你能够平安地减少层的大小以寻求验证损失的改善。不过,这有一个不可漠视的计算成本。
- 减少一个层并没有显著的帮忙,所以在这一点上,你可能会看到减少网络容量的回报越来越少。
应用双向的 RNNs
本节介绍的最初一项技术被称为双向 RNNs。双向 RNN 是一种常见的 RNN 变体,在某些工作上能够提供比一般 RNN 更大的性能。它常常被用于自然语言解决 – 你能够把它称为用于自然语言解决的深度学习的瑞士军刀。
值得注意的是,RNN 是程序依赖的,或者说是工夫依赖的:它们按程序解决其输出序列的时间段颠倒时间段能够齐全扭转 RNN 从序列中提取的示意。这正是它们在程序有意义的问题上体现良好的起因,如温度预测问题。双向 RNN 利用了 RNN 的程序敏感性:它包含应用两个惯例的 RNN,比方你曾经相熟的 layer\_gru 和 layer\_lstm,每个都从一个方向(按工夫程序和按反工夫程序)解决输出序列,而后合并它们的示意。通过双向解决一个序列,双向 RNN 能够辨认到可能被单向 RNN 疏忽的模式。
值得注意的是,本节中的 RNN 层按工夫程序解决了序列(较早的时间段在前),这可能是一个随便的决定。如果 RNN 按反时序解决输出序列,例如(较新的时间段在前),它们的体现是否足够好?让咱们在实践中尝试一下,看看会产生什么。训练你在本节第一个试验中应用的雷同的单层 GRU 网络,你会失去如下的后果。
反序 GRU 的体现甚至低于常识性基线,表明在这种状况下,工夫解决对你的办法的胜利很重要。这是很有情理的:底层的 GRU 层通常会在记忆最近的过来方面比记忆边远的过来方面做得更好,而对于这个问题来说,较近的天气数据点天然比拟早的数据点更具预测性(这就是常识性基线相当弱小的起因)。因而,按工夫顺序排列的图层的体现必然会优于倒序的版本。重要的是,对于许多其余问题,包含自然语言,这并不正确:凭直觉,一个词在了解一个句子中的重要性通常并不取决于它在句子中的地位。
让咱们在 LSTM IMDB 例子上尝试同样的技巧。
# 思考作为特色的词的数量
max_features <- 10000
# 剔除超过这个字数的文本
maxlen <- 500
# 反转序列
x\_train <- lapply(x\_train, rev)
x\_test <- lapply(x\_test, rev)
layer_lstm(units = 32)
history <- model %>% fit(
x\_train, y\_train,
epochs = 10,
batch_size = 128,
)
你失去的性能简直与按工夫顺序排列的 LSTM 雷同。值得注意的是,在这样的文本数据集上,倒序解决与按工夫程序解决一样好,这证实了这样的假如:只管词序在了解语言方面的确很重要,但你应用哪种程序并不要害。重要的是,在颠倒的序列上训练的 RNN 将与在原始序列上训练的 RNN 学习不同的表征,就像在事实世界中,如果工夫倒流,你会有不同的心理模型 – 如果你的生存中,你在第一天死亡,在最初一天出世。
在机器学习中,不同但有用的表征总是值得利用的,而且它们的差别越大越好:它们提供了一个新的角度来察看你的数据,辨认到了其余办法所脱漏的数据方面,因而它们能够帮忙进步工作的性能。
双向 RNN 利用这个想法来进步按工夫顺序排列的 RNN 的性能。它从两个方面察看其输出序列,取得潜在的更丰盛的表征,并辨认到可能被独自的工夫程序版本所脱漏的模式。
要在 Keras 中实例化一个双向 RNN,它须要一个递归层实例作为参数。创立这个递归层的第二个独立实例,并应用一个实例来解决按工夫顺序排列的输出序列,另一个实例来解决按相同顺序排列的输出序列。咱们在 IMDB 情感剖析工作上试试。
bidirectional(lstm(units = 32)
)
它的体现比之前尝试的一般 LSTM 略好,获得了超过 89% 的验证准确性。它仿佛也会更快地过拟合,这并不奇怪,因为双向层的参数是按工夫顺序排列的 LSTM 的两倍。通过一些正则化,双向办法很可能在这个工作中表现出色。
当初让咱们在温度上尝试同样的办法
bidirectional(layer_gru(units = 32),
) %>%
layer_dense(units = 1)
和一般的 layer_gru 的体现差不多。这很容易了解:所有的预测能力必须来自于网络中按工夫顺序排列的那一半,因为已知反工夫顺序排列的那一半在这个工作上体现严重不足。
进一步
为了进步温度预测问题的性能,你还能够尝试许多其余事件。
- 调整重叠设置中每个递归层的单元数量。目前的抉择基本上是任意的,因而可能是次优的。
- 调整 RMSprop 优化器应用的学习率。
- 尝试应用 layer\_lstm 而不是 layer\_gru。
- 尝试在递归层之上应用更大的密集连贯回归器:也就是说,一个更大的密集层,甚至是密集层的重叠。
- 最终在测试集上运行体现最好的模型(就验证 MAE 而言)。否则,你会开发出适度拟合的架构。
深度学习是一门艺术,而不是一门迷信。咱们能够提供指导方针,但最终,每个问题都是举世无双的;你必须依据教训来评估不同的策略。目前还没有任何实践可能当时精确地通知你应该怎么做能力最无效地解决问题。你必须进行迭代。
总结
- 在解决一个新问题时,最好首先为你抉择的指标建设常识性的基准。如果你没有一个基准,你就无奈判断你是否获得了真正的停顿。
- 先尝试简略的模型,以证实合理性。有时,一个简略的模型会成为你最好的抉择。
- 当你的数据的工夫程序很重要时,递归网络是一个很好的抉择。
- 为了在递归网络中应用 dropout,你应该应用工夫恒定的 dropout mask 和递归 dropout mask。
- 重叠的 RNN 比繁多的 RNN 层提供更多的示意能力。尽管它们在简单的问题(如机器翻译)上提供了显著较好的成果,但它们可能在较简略的问题体现个别。
- 双向的 RNNs,从两个方面看一个序列,在自然语言解决问题上很有用。但它们在序列数据上的体现并不突出,因为在这些数据中,近期的信息量要比序列的初始数据大得多。
留神:股市和机器学习
一些读者肯定会想把咱们在这里介绍的技术,在预测股票市场上的证券(或货币汇率等)的将来价格问题上进行尝试。市场与天然景象(如天气模式)有着十分不同的统计特色,当波及到 股市 时,过来的体现并不能很好地预测将来的回报 – 看后视镜是一种不好的驾驶形式。另一方面,机器学习实用于那些过来能很好地预测将来的数据集。