当前位置: 首页 > news >正文

深度学习处理时间序列(6)

RNN的高级用法

循环dropout(recurrent dropout)​:这是dropout的一种变体,用于在循环层中降低过拟合。

循环层堆叠(stacking recurrent layers)​:这会提高模型的表示能力(代价是更大的计算量)​。

双向循环层(bidirectional recurrent layer)​:它会将相同的信息以不同的方式呈现给RNN,可以提高精度并缓解遗忘问题。

我们将使用这3种方法来完善温度预测RNN.

利用循环dropout降低过拟合

我们回头来看基于LSTM的模型,它是第一个能够超越常识基准的模型。观察这个模型的训练曲线和验证曲线(图10-5)​,可以明显看出,尽管模型只有很少的单元,但很快就出现过拟合,训练损失和验证损失在几轮过后就开始明显偏离。你已经熟悉了降低过拟合的经典方法—dropout,即让某一层的输入单元随机为0,其目的是破坏该层训练数据中的偶然相关性。但如何在RNN中正确使用dropout,并不是一个简单的问题。人们早就知道,在循环层之前使用dropout会妨碍学习过程,而不会有助于正则化。2016年,Yarin Gal在他关于贝叶斯深度学习的博士论文中,确定了在RNN中使用dropout的正确方式:在每个时间步都应该使用相同的dropout掩码(相同模式的舍弃单元)​,而不是在不同的时间步使用随机变化的dropout掩码。此外,为了对GRU和LSTM等层的循环门得到的表示做正则化,还应该对该层的内部循环激活应用一个不随时间变化的dropout掩码(循环dropout掩码)​。在每个时间步使用相同的dropout掩码,可以让神经网络沿着时间传播其学习误差,而随时间随机变化的dropout掩码则会破坏这个误差信号,不利于学习过程。

Keras中的每个循环层都有两个与dropout相关的参数:一个是dropout,它是一个浮点数,指定该层输入单元的dropout比率;另一个是recurrent_dropout,指定循环单元的dropout比率。对于第一个LSTM示例,我们向LSTM层中添加循环dropout,看一下它对过拟合的影响,如代码清单10-22所示。由于使用了dropout,我们不需要过分依赖网络尺寸来进行正则化,因此我们将使用具有两倍单元个数的LSTM层,希望它的表示能力更强(如果不使用dropout,这个网络会马上开始过拟合,你可以试试看)​。由于使用dropout正则化的网络总是需要更长时间才能完全收敛,因此我们将模型训练轮数设为原来的5倍。

代码清单10-22 训练并评估一个使用dropout正则化的LSTM模型

inputs = keras.Input(shape=(sequence_length, raw_data.shape[-1]))
x = layers.LSTM(32, recurrent_dropout=0.25)(inputs)
x = layers.Dropout(0.5)(x)----这里在LSTM层之后还添加了一个Dropout层,对Dense层进行正则化
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

callbacks = [
    keras.callbacks.ModelCheckpoint("jena_lstm_dropout.keras",
                                    save_best_only=True)
]
model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"])
history = model.fit(train_dataset,
                    epochs=50,
                    validation_data=val_dataset,
                    callbacks=callbacks)

模型结果如图10-11所示。成功!模型在前20轮中不再过拟合。验证MAE低至2.27摄氏度(比不使用机器学习的基准改进了7%)​,测试MAE为2.45摄氏度(比基准改进了6.5%)​,还不错

在这里插入图片描述

RNN的运行时性能

对于参数很少的循环模型(比如本章中的模型)​,在多核CPU上的运行速度往往比GPU上快很多,因为这种模型只涉及小矩阵乘法,而且由于存在for循环,因此乘法链无法很好地并行化。但较大的RNN则可以显著地受益于GPU运行时。使用默认关键字参数在GPU上运行Keras LSTM层或GRU层时,该层将利用cuDNN内核。这是由NVIDIA提供的低阶底层算法实现,它经过高度优化​。cuDNN内核有利有弊:速度快,但不够灵活。如果你想做一些默认内核不支持的操作,将会遭受严重的降速,这或多或少会迫使你坚持使用NVIDIA提供的操作。例如,LSTM和GRU的cuDNN内核不支持循环dropout,因此在层中添加循环dropout,会使运行时变为普通TensorFlow实现,这在GPU上的速度通常是原来的1/5~1/2(尽管计算成本相同)​。如果无法使用cuDNN,有一种方法可以加快RNN层的运行速度,那就是将RNN层展开(unroll)​。展开for循环是指去掉循环,将循环中的内容重复相应次。对于RNN的for循环,展开有助于TensorFlow对底层计算图进行优化。然而,这样做也会大大增加RNN的内存消耗,因此,它只适用于相对较小的序列(大约100个时间步或更少)​。另外请注意,只有当模型事先知道数据中的时间步数时(也就是说,向初始Input()传入的shape不包含None)​,才能使用这种方法。它的工作原理如下。

inputs = keras.Input(shape=(sequence_length, num_features))---- sequence_length不能是None
x = layers.LSTM(32, recurrent_dropout=0.2, unroll=True)(inputs)----传入unroll=True将该层展开

循环层堆叠

模型不再过拟合,但似乎遇到了性能瓶颈,所以我们应该考虑增加神经网络的容量和表示能力。回想一下机器学习的通用工作流程,增大模型容量通常是好的做法,直到过拟合成为主要障碍(假设你已经采取了基本措施来降低过拟合,比如使用dropout)​。只要过拟合不是太严重,那么模型就很可能容量不足。增加网络容量的通常做法是增加每层单元个数或添加更多的层。循环层堆叠是构建更加强大的循环网络的经典方法,比如,不久之前谷歌翻译算法就是7个大型LSTM层的堆叠—这个模型很大。在Keras中堆叠循环层,所有中间层都应该返回完整的输出序列(一个3阶张量)​,而不是只返回最后一个时间步的输出。前面说过,这可以通过指定return_sequences=True来实现。在下面这个示例中,我们尝试堆叠两个使用dropout正则化的循环层,如代码清单10-23所示。不同的是,我们将使用门控循环单元(gated recurrent unit,GRU)层代替LSTM层。GRU与LSTM非常类似,你可以将其看作LSTM架构的精简版本。它由Kyunghyun Cho等人于2014年提出,当时RNN刚刚开始在不大的研究群体中重新引起人们的兴趣。

代码清单10-23 训练并评估一个使用dropout正则化的堆叠GRU模型

inputs = keras.Input(shape=(sequence_length, raw_data.shape[-1]))
x = layers.GRU(32, recurrent_dropout=0.5, return_sequences=True)(inputs)
x = layers.GRU(32, recurrent_dropout=0.5)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

callbacks = [
    keras.callbacks.ModelCheckpoint("jena_stacked_gru_dropout.keras",
                                    save_best_only=True)
]
model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"])
history = model.fit(train_dataset,
                    epochs=50,
                    validation_data=val_dataset,
                    callbacks=callbacks)
model = keras.models.load_model("jena_stacked_gru_dropout.keras")
print(f"Test MAE: {model.evaluate(test_dataset)[1]:.2f}")

模型结果如图10-12所示。测试MAE为2.39摄氏度(比基准改进了8.8%)​。可以看到,增加一层确实对结果有所改进,但效果并不明显。此时你可能会发现,增加网络容量的回报在逐渐减小。

在这里插入图片描述

http://www.dtcms.com/a/98169.html

相关文章:

  • 自学-python-基础-注释、数据类型、运算符、判断、循环
  • 树莓派超全系列文档--(13)如何使用raspi-config工具其二
  • 中断管理常用API详解(三)
  • flatMap 介绍及作用
  • C#连接sqlite数据库实现增删改查
  • 大模型最新面试题系列:微调篇之微调框架(二)
  • AI赋能python数据处理、分析与预测操作流程
  • Vue背景介绍+声明式渲染+数据响应式
  • 基于Baklib的云内容中台落地实践
  • JMeter运行日志详细分析
  • Kafka Stream从入门到精通:构建高吞吐、低延迟的实时流处理应用
  • 力扣.旋转矩阵Ⅱ
  • sqli-labs靶场 less6
  • Android 串口配置
  • 双磁条线跟踪控制
  • LJF-Framework 第12章 LjfFilter拦截器设计
  • hbuilderx打包iOS上传苹果商店的最简流程
  • AI坦克智能决策:MOE模型的动态专家协作与加权融合
  • Python自动化模块:开启高效编程新时代
  • 乘AI之势,劲吹正能量之风:生成式人工智能(GAI)认证引领新时代
  • AudioFlinger与AudioPoliceManager初始化流程
  • unity客户端面试高频2(自用)
  • Redis底层数据结构实现
  • Python 科学计算
  • QML输入控件:Dial外观深度定制(4)
  • angr基础学习
  • 基于改进粒子群算法的多目标分布式电源选址定容规划(附带Matlab代码)
  • 【区块链安全 | 第十篇】智能合约概述
  • Unity编辑器功能及拓展(1) —特殊的Editor文件夹
  • Linux 一键安装 Docker 的万能脚本