16现代循环神经网络—深度循环与双向循环
目录
-
-
1.深度循环神经网络
-
- 回顾:循环神经网络
- 总结
- 简洁代码实现
-
2.双向循环神经网络
-
- 隐马尔可夫模型中的动态规划
- 双向模型
- 模型的计算代价及其应用
- 总结
- 代码实现
-
1.深度循环神经网络
回顾:循环神经网络

-
如何将循环神经网络变深,以获得更多的非线性? * 通过添加多个隐藏层的方式来实现 (和 MLP 没有本质区别),每个隐藏状态都连续地传递到当前层的下一个时间步和下一层的当前时间步


-
类似于多层感知机,隐藏层数目 和隐藏单元数目 都是超参数(它们是可以进行调整的)
-
使用门控循环单元 或长短期记忆网络 的隐状态替代上图中深度循环神经网络中的隐状态计算,就能够很容易地得到深度门控循环神经网络 或长短期记忆神经网络
总结
深度循环神经网络使用多个隐藏层来获得更多的非线性性
* GRU、RNN、LSTM 在结构上都是相同的,**只是隐状态 H 的计算方式有区别,所以它们加深神经网络的原理都是相同的**
在深度循环神经网络中,隐状态的信息被传递到当前层的下一时间步和下一层的当前时间步
存在许多不同风格的深度循环神经网络,如长短期记忆网络、门控循环单元或经典循环神经网络
深度循环神经网络需要大量的调参(如学习率和修剪)来确保合适的收敛,模型的初始化也需要谨慎
简洁代码实现
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
num_inputs = vocab_size
device = d2l.try_gpu()
#num_inputs输入纬度 num_hiddens隐藏层大小 num_layers隐藏层层数
lstm_layer = nn.LSTM(num_inputs, num_hiddens, num_layers)
#输出层
model = d2l.RNNModel(lstm_layer, len(vocab))
model = model.to(device)
代码解读
2.双向循环神经网络
-
对于序列来讲,通常假设的目标是:在给定观测的情况下(如在时间序列的上下文中或语言模型的上下文中),对下一个输出进行建模。虽然这是一个典型的场景,但并不是唯一的
-
对于序列模型来讲,可以从前往后看,也可以从后往前看,在某些情况下是可以的,有的情况下是不行的

-
取决于过去和未来的上下文,可以填很不一样的词
-
目前为止RNN只能看过去
-
在填空的时候,我们也可以看未来
隐马尔可夫模型中的动态规划
假设有一个隐变量模型:在任意时间步 t ,假设存在某个隐变量 ht ,通过概率 P(xt | ht) 控制观测到的 xt。此外,任何 ht -> h(t+1) 转移都是由一些状态转移概率 P(h(t+1) | ht)给出,则这个概率图模型就是一个隐马尔可夫模型(hidden Markov model,HMM)

双向模型

- 在循环神经网络中,只有一个在前向模式下**“从第一个次元开始运行”的循环神经网络。如果想要循环网络获得与隐马尔可夫模型类似的前瞻能力,只需要增加一个“从最后一个词元开始从后向前运行”的循环神经网络。**
- 双向循环神经网络的架构与隐马尔可夫模型中的动态规划的前向和后向递归没有太大的区别 ,主要的区别在于:隐马尔科夫模型中的方程具有特定的统计意义,而双向循环神经网络只能当作是通用的、可学习的函数(这种转变集中体现了现代深度网络的设计原则: 首先使用经典统计模型的函数依赖类型,然后将其参数化为通用形式。)
- 双向循环神经网络的隐藏层中有两个隐状态(前向隐状态和反向隐状态 ,通过添加反向传递信息的隐藏层来更灵活地处理反向传递的信息):
- 以输入 X1 为例,当输入 X1 进入到模型之后,当前的隐藏状态(右箭头,前向隐状态)放入下一个时间步的状态中去;
- X2 更新完隐藏状态之后,将更新后的隐藏状态传递给 X1 的隐藏状态(左箭头,反向隐状态),将两个隐藏状态(前向隐状态和反向隐状态)合并在一起,就得到了需要送入输出层的隐状态 Ht (在具有多个隐藏层的深度双向循环神经网络中,则前向隐状态和反向隐状态这两个隐状态会作为输入继续传递到下一个双向层(具有多个隐藏层的深度双向循环神经网络其实就是多个双向隐藏层的叠加)),最后输出层计算得到输出 Ot

实现:
- 将输入复制一遍,一份用于做前向的时候,正常的隐藏层会得到一些输出;
- 另一份用于做反向的时候,反向的隐藏层会得到另外一些输出,然后进行前后顺序颠倒。将正向输出和颠倒顺序后的反向输出进行合并(concat),就能得到最终的输出了
模型的计算代价及其应用
双向循环神经网络的一个关键特性是:使用来自序列两端的信息来估计输出
- 使用过去和未来的观测信息来预测当前的观测,因此并不适用于预测下一个词元的场景,因为在预测下一个词元时,并不能得知下一个词元的下文,因为不会得到很好的精度
- 如果使用双向循环神经网络预测下一个词元,尽管在训练的时候能够利用所预测词元过去和未来的数据(也就是所预测词元的上下文)来估计所预测的词元,但是在测试的时候,模型的输入只有过去的数据(也就是所预测词所在位置之前的信息),所以会导致精度很差
此外,双向循环神经网络的计算速度非常慢
- 主要原因是网络的前向传播需要在双向层中进行前向和后向递归,并且网络的反向传播也以依赖于前向传播的结果,因此梯度求解将有一个非常长的链
双向层在实际中的时用的比较少,仅仅应用于部分场合:
-
填充缺失的单词
-
词元注释 (如命名实体识别)
-
作为序列处理流水线中的一个步骤对序列进行编码 (如机器翻译)

-
双向 LSTM 不适合做推理,几乎不能用于预测下一个词 ,因为为了得到隐藏状态 H ,既要看到它之前的信息,又要看到之后的信息,因为在推理的时候没有之后的信息,所以是做不了推理的
-
双向循环神经网络主要的作用是对句子做特征提取 ,比如在做翻译的时候,给定一个句子去翻译下一个句子,那么可以用双向循环神经网络来做已给定句子的特征提取;或者是做改写等能够看到整个句子的应用场景下,做整个句子的特征提取
总结
双向循环神经网络通过反向更新的隐藏层来利用方向时间信息
在双向循环神经网络中,每个时间步的隐状态由当前时间步的前后数据同时决定
双向循环神经网络与概率图模型中的“前向-后向”算法具有相似性
双向循环神经网络主要用于序列编码和给定双向上下文的观测估计,通常用来对序列抽取特征、填空,而不是预测未来
由于梯度链更长,因此双向循环神经网络的训练代价非常高
代码实现
由于双向循环神经网络使用了过去的和未来的数据, 所以我们不能盲目地将这一语言模型应用于任何预测任务。 尽管模型产出的困惑度是合理的, 该模型预测未来词元的能力却可能存在严重缺陷。
import torch
from torch import nn
from d2l import torch as d2l
# 加载数据
batch_size, num_steps, device = 32, 35, d2l.try_gpu()
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
# 通过设置“bidirective=True”来定义双向LSTM模型
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
num_inputs = vocab_size
#与LSTM相比 只需添加一个bidirectional=True 就可以自动反向
lstm_layer = nn.LSTM(num_inputs, num_hiddens, num_layers, bidirectional=True)
model = d2l.RNNModel(lstm_layer, len(vocab))
model = model.to(device)
# 训练模型
num_epochs, lr = 500, 1
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
odel = model.to(device)
# 训练模型
num_epochs, lr = 500, 1
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
代码解读
