深度递归神经网络
引用翻译:《动手学深度学习》
到目前为止,我们只讨论了具有单一单向隐藏层的递归神经网络。在其中,潜变量和观测值如何互动的具体函数形式是相当随意的。只要我们有足够的灵活性来模拟不同类型的相互作用,这并不是一个大问题。然而,对于一个单层,这可能是相当具有挑战性的。在感知器的情况下,我们通过添加更多的层来解决这个问题。在RNN中,这就有点棘手了,因为我们首先需要决定如何和在哪里增加额外的非线性。我们下面的讨论主要集中在LSTM上,但它也适用于其他序列模型。
-
我们可以在门控机制中增加额外的非线性。也就是说,我们可以不使用单一的感知器,而使用多层。这使得LSTM的机制没有改变。相反,它使其更加复杂。如果我们相信LSTM机制描述了潜伏变量自回归模型工作的某种形式的普遍真理,这将是有意义的。
-
我们可以把多层的LSTM堆叠在一起。这样做的结果是,由于几个简单层的组合,机制更加灵活。特别是,数据可能在堆栈的不同层次上都是相关的。例如,我们可能希望在高层次上保持关于金融市场状况(熊市或牛市)的高层次数据,而在低层次上我们只记录较短期的时间动态。
除了这些抽象的讨论,通过回顾下图,可能最容易理解我们感兴趣的模型系列。它描述了一个具有L个隐藏层的深度递归神经网络。每个隐藏状态都被连续传递给当前层的下一个时间步长和当前时间步长的下一个层。
一、功能依赖性
在时间步骤t,我们假设有一个minibatch 𝑋𝑡∈𝑅𝑛×𝑑(例子数量:𝑛 ,输入数量:𝑑 )。隐层的隐藏状态𝑙(𝑙=1,…。 ,𝑇)是𝐻(𝑙)𝑡∈𝑅𝑛×ℎ(隐藏单元数:ℎ ),输出层变量是𝑂𝑡∈𝑅(𝑛×𝑞)(输出数:𝑞 ),隐层激活函数𝑓𝑙,用于层𝑙。我们像以前一样,用𝑋𝑡作为输入计算第1层的隐藏状态。对于所有后续层,则使用前一层的隐藏状态来代替它。
H
t
(
1
)
=
f
1
(
X
t
,
H
t
−
1
(
1
)
)
H_t^{(1)} = f_1(X_t , H_{t−1}^{(1)})
Ht(1)=f1(Xt,Ht−1(1))
H
t
(
1
)
=
f
1
(
H
t
(
1
−
1
)
,
H
t
−
1
(
1
)
)
H_t^{(1)} = f_1(H_{t}^{(1-1)} , H_{t−1}^{(1)})
Ht(1)=f1(Ht(1−1),Ht−1(1))
最后,输出层的输出只基于隐藏层的隐藏状态𝐿。我们使用输出函数𝑔来解决这个问题。
O t = g ( H t ( L ) ) O_t = g(H_t^{(L)}) Ot=g(Ht(L))
就像多层感知器一样,隐藏层的数量𝐿和隐藏单元的数量ℎ是超参数。特别是,我们可以选择一个普通的RNN、GRU或LSTM来实现这个模型。
二、简洁的实现
幸运的是,实现多层RNN所需的许多后勤细节在Gluon中都是现成的。为了保持简单,我们只说明了使用这种内置功能的实现。该代码与我们之前用于LSTM的代码非常相似。事实上,唯一的区别是,我们明确指定了层数,而不是选择默认的单层。让我们首先导入相应的模块和数据。
import sys
sys.path.insert(0, '..')
import d2l
import torch
import torch.nn as nn
from d2l import RNNModel
from d2l import load_data_time_machine
from d2l import train_and_predict_rnn_nn
torch.set_default_tensor_type('torch.cuda.FloatTensor')
corpus_indices, vocab = load_data_time_machine()
架构决定(参数等)与前几节的决定非常相似。我们选取的输入和输出的数量与我们拥有的不同标记相同,即vocab_size。
隐藏单元的数量仍然是256,我们保留了100的学习率。唯一的区别是,我们现在选择了一个数量不小的层num_layers = 2。由于该模型的训练速度较慢,我们使用3000次迭代。
num_inputs, num_hiddens, num_layers, num_outputs = len(vocab), 256, 2, len(vocab)
ctx = d2l.try_gpu()
num_epochs, num_steps, batch_size, lr, clipping_theta = 20, 35, 32, 5, 1
prefixes = ['traveller', 'time traveller']
print('Using', ctx)
Using cpu
三、训练
实际的调用逻辑与之前相同,我们重新使用train_and_predict_rnn_gluon。唯一不同的是,我们现在用LSTM实例化了两层。这种相当复杂的结构和大量的历时大大降低了训练速度。
def init_lstm_state(batch_size, num_hiddens, device):
return (torch.zeros(size=(batch_size, num_hiddens), device=device),
torch.zeros(size=(batch_size, num_hiddens), device=device))
lstm_layer = nn.LSTM(input_size=num_inputs, hidden_size=num_hiddens)
model = RNNModel(lstm_layer, num_hiddens, len(vocab))
model.to(ctx)
train_and_predict_rnn_nn(model, num_hiddens, init_lstm_state, corpus_indices, vocab,
ctx, num_epochs, num_steps, lr,
clipping_theta, batch_size, prefixes, 2)
四、摘要
-
在深度递归神经网络中,隐藏的状态信息被传递到当前层的下一个时间步骤和当前时间步骤的下一个层。
-
存在许多不同类型的深度RNNs,如LSTMs、GRU或常规RNNs。方便的是,这些模型都可以作为Gluon中rnn模块的一部分。
-
模型的初始化需要注意。总的来说,深层RNN需要相当多的工作(学习率、剪切等)以确保适当的收敛。