TensorFlow深度学习实战(13)——循环神经网络详解
- 0. 前言
- 1. 基本循环神经网络单元
- 1.1 循环神经网络工作原理
- 1.2 时间反向传播
- 1.3 梯度消失和梯度爆炸问题
- 2. RNN 单元变体
- 2.1 长短期记忆
- 2.2 门控循环单元
- 2.3 Peephole LSTM
- 3. RNN 变体
- 3.1 双向 RNN
- 3.2 状态 RNN
- 4. RNN 拓扑结构
- 小结
- 系列链接
0. 前言
循环神经网络 (Recurrent Neural Network
, RNN
) 是一类特殊的神经网络结构,广泛应用于处理和分析序列数据,如文本、语音、时间序列等。与传统的神经网络不同,RNN
具有记忆功能,可以通过循环连接处理序列中各个元素之间的依赖关系。
1. 基本循环神经网络单元
1.1 循环神经网络工作原理
传统的多层感知器神经网络假设所有输入都彼此独立,但这种假设对许多类型的序列数据并不成立。例如,句子中的单词、乐曲中的音符、随时间变化的股票价格,甚至化合物中的分子,都是一个元素的出现取决于其前面元素的序列。
循环神经网络 (Recurrent Neural Network
, RNN
) 单元通过使用隐藏状态(或记忆)来包含这种依赖关系,该隐藏状态保存到目前为止所见内容的要点。任意时刻的隐藏状态值是前一时刻的隐藏状态值和当前时刻输入值的函数,即:
h t = ϕ ( h t − 1 , x t ) h_t=\phi(h_{t-1},x_t) ht=ϕ(ht−1,xt)
其中, h t h_t ht 和 h t − 1 h_{t-1} ht−1 分别是时刻 t t t 和 t − 1 t-1 t−1 的隐藏状态值,而 x t x_t xt 是时刻 t t t 处的输入值。需要注意的是,以上方程是循环的,也就是说, h t − 1 h_{t-1} ht−1 可以用 h t − 2 h_{t-2} ht−2 和 x t − 1 x_{t-1} xt−1 表示,依此类推,直至序列的开始,这就是 RNN
编码和整合任意长度序列的信息的方式。
我们还可以 RNN
单元以图形方式表示,如下图所示。在时刻 t t t,单元有一个输入 x t x_t xt 和输出 o t o_t ot。输出的一部分 o t o_t ot (由隐藏状态 h t h_t ht 表示)会反馈到单元中,以便在后续时刻 t + 1 t+1 t+1 中使用。
与传统神经网络一样,学习到的参数存储为权重矩阵,RNN
的参数由三个权重矩阵 u u u、 v v v 和 w w w 定义,分别对应输入、输出和隐藏状态的权重:
上图还展示了 RNN
单元的展开视图,展开只意味着我们将网络绘制为完整序列的形式,假设网络只有三个时刻,适用于处理具有三个元素的序列。需要注意的是,权重矩阵 u u u、 v v v 和 w w w 在每个时刻之间是共享的。这是因为我们在每个时刻应用相同的操作到不同的输入上,在所有时刻共享这些权重极大的减少了 RNN
需要学习的参数数量。
我们还可以通过方程式将 RNN
描述为计算图。时刻 t t t 处的 RNN
的内部状态由隐藏向量 h t h_t ht 的值给出,该隐藏向量是权重矩阵 w w w 和时刻 t − 1 t-1 t−1 处的隐藏状态 h t − 1 h_{t-1} ht−1 的乘积,再加上权重矩阵 u u u 与时刻 t t t 处的输入 x t x_t xt 的乘积,然后通过 tanh
激活函数传递。选择 tanh
而不是 sigmoid
等其他激活函数,是因为在实践中 tanh
更有效,并有助于解决梯度消失问题。
为了方便,在描述不同类型的 RNN
结构的方程中,我们省略了显式的偏置项,将其合并到矩阵中。例如,以下 n
维空间中的直线方程,其中 w 1 w_1 w1 到 w n w_n wn 指的是直线在每个维度上的系数,偏置 b b b 指的是每个维度上的 y y y 截距:
y = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + b y=w_1x_1+w_2x_2+\cdots+w_nx_n+b y=w1x1+w2x2+⋯+wnxn+b
我们可以将方程重写为矩阵形式如下:
y = w x + b y=wx+b y=wx+b
其中, w w w 是形状为 ( m , n ) (m, n) (m,n) 的矩阵, b b b 是形状为 ( m , 1 ) (m, 1) (m,1) 的向量, m m m 是数据集中的样本数, n n n 是每个样本对应的特征数。等效地,我们可以通过将 b b b 向量视为 w w w 的单位特征列,将其折叠到矩阵 w w w 中来消除向量 b b b:
y = w 1 x 1 + w 2 x 2 + ⋯ + w n x n + w 0 ( 1 ) = w ′ x y=w_1x_1+w_2x_2+\cdots+w_nx_n+w_0(1)=w'x y=w1x1+w2x2+⋯+wnxn+w0(1)=w′x
其中, w ′ w' w′ 是形状为 ( m , n + 1 ) (m, n+1) (m,n+1) 的矩阵,最后一列包含 b b b 的值,这样得到的形式更为紧凑,也更容易理解和记忆。
在时刻 t t t 处的输出向量 o t o_t ot 是权重矩阵 v v v 和隐藏状态 h t h_t ht 的乘积经过 softmax
激活得到的,得到的输出向量为输出概率:
h t = t a n h ( w h t − 1 + u x t ) o t = s o f t m a x ( v h t ) h_t= tanh(wh_{t-1} +ux_t)\\ o_t=softmax(vh_t) ht=tanh(wht−1+uxt)ot=softmax(vht)
Keras
提供了 SimpleRNN
循环层(包含基本 RNN
单元的所有逻辑),以及高级变体如长短期记忆 (Long Short Term Memory
, LSTM
) 和门控循环单元 (Gated Recurrent Unit
, GRU
)。严格来说,使用这些层构建模型并不需要理解它们的工作原理,然而,了解它们的结构和方程在需要构建专门的 RNN
单元以解决特定问题时很有帮助。
我们已经了解了数据如何通过 RNN
单元前向传播,即如何组合其输入和隐藏状态以产生输出和下一个隐藏状态,接下来,我们介绍梯度的反向传播过程,这一过程称为时间反向传播 (Backpropagation Through Time
, BPTT
)。
1.2 时间反向传播
与传统的神经网络一样,训练 RNN
也涉及到梯度的反向传播。不同之处在于,由于权重在所有时刻是共享的,每个输出的梯度不仅取决于当前时刻,还取决于之前的时刻,这一过程称为时间反向传播 (Backpropagation Through Time
, BPTT
)。由于在 RNN
中权重 u u u、 v v v 和 w w w 在不同时刻间共享,因此需要对各个时刻的梯度进行求和,这是传统反向传播和 BPTT
之间的关键区别。
例如,在如下具有五个时刻的 RNN
中。在前向传播期间,网络生成时刻 t t t 处的预测 o ^ t \hat o_t o^t,将其与标签 o t o_t ot 进行比较以计算损失 L t L_t Lt。在反向传播过程中(用虚线表示),计算每个时刻的损失对权重 u u u、 v v v 和 w w w 的梯度,并用梯度的总和更新参数:
损失函数对 w w w 的梯度如下方程所示,这个权重是导致梯度消失和梯度爆炸问题的原因。梯度消失和梯度爆炸问题表现为损失的梯度接近零或无穷大,使得网络难以训练。为了理解为什么会发生这种情况,考虑我们之前介绍的 SimpleRNN
的方程,隐藏状态 h t h_t ht 依赖于 h t − 1 h_{t-1} ht−1,而 h t − 1 h_{t-1} ht−1 又依赖于 h t − 2 h_{t-2} ht−2,依此类推:
∂ L ∂ w = ∑ t ∂ L t ∂ w \frac{\partial L}{\partial w}=\sum_t\frac{\partial L_t}{\partial w} ∂w∂L=t∑∂w∂Lt
观察时刻 t = 3 t=3 t=3 时的梯度情况,根据链式法则,损失函数相对于 w w w 的梯度可以分解为三个子梯度的乘积。隐藏状态 h 2 h_2 h2 相对于 w w w 的梯度可以进一步分解为每个隐藏状态相对于前一个隐藏状态的梯度之和。最后,每个隐藏状态相对于前一个隐藏状态的梯度可以进一步分解为当前隐藏状态相对于前一个隐藏状态的梯度的乘积:
∂ L 3 ∂ w = ∂ L 3 ∂ o ^ 3 ∂ o ^ 3 ∂ h 3 ∂ h 3 ∂ w = ∑ t = 0 3 ∂ L 3 ∂ o ^ 3 ∂ o ^ 3 ∂ h 3 ∂ h 3 ∂ h t ∂ h t ∂ w = ∑ t = 0 3 ∂ L 3 ∂ o ^ 3 ∂ o ^ 3 ∂ h 3 ( ∏ j = t + 1 3 ∂ h j ∂ h j − 1 ) ∂ h t ∂ w \frac{\partial L_3}{\partial w}=\frac{\partial L_3}{\partial \hat o_3}\frac{\partial \hat o_3}{\partial h_3}\frac{\partial h_3}{\partial w}=\sum_{t=0}^3\frac{\partial L_3}{\partial \hat o_3}\frac{\partial \hat o_3}{\partial h_3}\frac{\partial h_3}{\partial h_t}\frac{\partial h_t}{\partial w}=\sum_{t=0}^3\frac{\partial L_3}{\partial \hat o_3}\frac{\partial \hat o_3}{\partial h_3}(\prod _{j=t+1}^3\frac{\partial h_j}{\partial h_{j-1}})\frac{\partial h_t}{\partial w} ∂w∂L3=∂o^3∂L3∂h3∂o^3∂w∂h3=t=0∑3∂o^3∂L3∂h3∂o^3∂ht∂h3∂w∂ht=t=0∑3∂o^3∂L3∂h3∂o^3(j=t+1∏3∂hj−1∂hj)∂w∂ht
类似的计算同样可以用于计算损失 L 0 L_0 L0 到 L 4 L_4 L4 相对于 w w w 的梯度,并将它们累加到W的梯度更新中。
1.3 梯度消失和梯度爆炸问题
BPTT
对梯度消失和梯度爆炸问题特别敏感,原因在于表示损失相对于 w w w 的梯度的最终公式中的乘积部分。假设隐藏状态相对于前一隐藏状态的各个梯度都小于 1
。那么随着跨多个时刻进行反向传播,梯度的乘积变得越来越小,最终导致梯度消失的问题。同样地,如果梯度大于 1
,乘积会越来越大,最终导致梯度爆炸的问题。
在以上两种情况中,梯度爆炸更容易被检测到,因为梯度会变得非常大并转化为 NaN
,导致训练过程崩溃。可以通过预定义阈值裁剪梯度来控制梯度爆炸,TensorFlow
可以通过在优化器构建期间使用 clipvalue
或 clipnorm
参数裁剪梯度,或者通过 tf.clip_by_value
显式裁剪梯度。
梯度消失会导致来自较远时刻的梯度对学习过程没有贡献,因此 RNN
最终无法学习到任何长期依赖关系。尽管有多种方法可以降低梯度消失问题的影响,如正确初始化 w w w 矩阵、使用更强大的正则化、使用 ReLU
代替 tanh
激活函数以及使用无监督方法预训练 RNN
层,但最佳的解决方案是使用 LSTM
或 GRU
架构,这些架构旨在更有效地处理梯度消失问题并学习长期依赖关系。
2. RNN 单元变体
2.1 长短期记忆
长短期记忆 (Long Short Term Memory
, LSTM
) 是 SimpleRNN
单元的一种变体,能够学习数据中的长期依赖关系。LSTM
在多种问题上具有优异表现,是最广泛使用的 RNN
变体。
SimpleRNN
通过 tanh
层将前一个时刻的隐藏状态和当前输入结合起来实现循环。LSTM
也以类似的方式实现循环,但不同于单一的 tanh
,LSTM
中有四个流程以特定的方式相互作用。下图展示了在时刻 t t t 时应用于隐藏状态的变换过程:
整体来看似乎很复杂,逐个组件分解便于理解。图顶部的横线代表单元的内部状态(也称记忆) c c c。底部的横线代表隐藏状态 h h h,而 i i i、 f f f 和 o o o 门则是 LSTM
处理梯度消失问题的机制。在训练期间,LSTM
学习这些门的参数。
理解 LSTM
单元内部各个门工作机制的另一种方式是利用数学方程,这些方程描述了如何从前一时时刻的隐藏状态 h t − 1 h_{t-1} ht−1 计算时刻 t t t 的隐藏状态 h t h_t ht 的值。总的来说,基于方程的描述往往更清晰、更简洁。表示 LSTM
的方程组如下:
i = σ ( w i h t − 1 + u i x t + v i ) f = σ ( w f h t − 1 + u f x t + v f ) o = σ ( w o h t − 1 + u o x t + v o ) g = tanh w g h t − 1 + u g x t c t = ( f ∗ c t − 1 ) + ( g ∗ i ) h t = tanh ( c t ) ∗ o i=\sigma(w_ih_{t-1}+u_ix_t+v_i)\\ f=\sigma(w_fh_{t-1}+u_fx_t+v_f)\\ o=\sigma(w_oh_{t-1}+u_ox_t+v_o)\\ g=\text{tanh}w_gh_{t-1}+u_gx_t\\ c_t=(f\ast c_{t-1})+(g\ast i)\\ h_t=\text{tanh}(c_t)\ast o i=σ(wiht−1+uixt+vi)f=σ(wfht−1+ufxt+vf)o=σ(woht−1+uoxt+vo)g=tanhwght−1+ugxtct=(f∗ct−1)+(g∗i)ht=tanh(ct)∗o
其中, i i i、 f f f 和 o o o 分别表示输入门 (input gate
)、遗忘门 (forget gate
) 和输出门 (output gate
)。它们使用相同的方程计算,但使用不同的参数矩阵 ( w i w_i wi、 u i u_i ui、 w f w_f wf、 u f u_f uf 和 w o w_o wo、 u o u_o uo)。sigmoid
函数将这些门的输出限制在 0
到 1
之间,因此生成的输出向量可以与另一个向量逐元素相乘,以定义第二个向量能通过第一个向量的程度。
遗忘门定义了之前隐藏状态 h t − 1 h_t-1 ht−1 通过的量,输入门定义了新计算的当前输入 x t x_t xt 的状态通过的量,而输出门定义了将内部状态暴露给下一层的量。内部隐藏状态 g g g 是基于当前输入 x t x_t xt 和前一个隐藏状态 h t − 1 h_{t-1} ht−1 计算的。需要注意的是, g g g 的方程与 SimpleRNN
的方程相同,但在 LSTM
中会通过输入门 i i i 的输出进行调节。
给定 i i i、 f f f、 o o o 和 g g g,可以计算时间刻 t t t 的单元状态 c t c_t ct,方法是将时刻 t − 1 t-1 t−1 处的单元状态 c t − 1 c_{t-1} ct−1 乘以遗忘门 f f f 的值,再加上状态 g g g 乘以输入门 i i i 的值。这本质上是将前一个单元状态与新输入结合起来的方法,将遗忘门设为 0
可以忽略旧状态,将输入门设为 0
可以忽略新计算出的状态。最后,时刻 t t t 处的隐藏状态 h t h_t ht 计算为时刻 t t t 处的单元状态 c t c_t ct 乘以输出门 o o o。
需要注意的是,LSTM
可以直接替代 SimpleRNN
单元,区别在于 LSTM
对梯度消失问题具有更强的抵抗能力。我们可以在网络中直接使用 LSTM
替换 RNN
单元,通常情况下,网络的训练结果会更好,相应的训练时间可能会更长。TensorFlow
还提供了 ConvLSTM2D
实现,其中矩阵乘法被卷积算子取代。
2.2 门控循环单元
门控循环单元 (Gated Recurrent Unit
, GRU
) 是 LSTM
的一种变体。它保留了 LSTM
对梯度消失问题的抵抗力,但其内部结构更简单,更新其隐藏状态所需的计算更少,因此训练速度更快。
与 LSTM
单元中的输入门 i i i、遗忘门 f f f 和输出门 o o o 不同,GRU
单元具有两个门:更新门 (update gate
) z z z 和重置门 (reset gate
) r r r。更新门定义了保留多少先前状态,而重置门定义了如何将新输入与先前状态结合。与 LSTM
不同,没有像 LSTM
那样与隐藏状态不同的持久性单元状态。
GRU
单元定义了如何基于前一个时刻的隐藏状态 h t − 1 h_{t-1} ht−1 计算时刻 t t t 的隐藏状态 h t h_t ht:
z = σ ( w z h h − 1 + u z x t ) r = σ ( w r h h − 1 + u r x t ) c = tanh ( w c ( h t − 1 ∗ r ) + u c x t ) h t = ( z ∗ c ) + ( ( 1 − z ) ∗ h t − 1 ) z=\sigma(w_zh_{h-1}+u_zx_t)\\ r=\sigma(w_rh_{h-1}+u_rx_t)\\ c=\text{tanh}(w_c(h_{t-1}\ast r)+u_cx_t)\\ h_t=(z\ast c)+((1-z)\ast h_{t-1})\\ z=σ(wzhh−1+uzxt)r=σ(wrhh−1+urxt)c=tanh(wc(ht−1∗r)+ucxt)ht=(z∗c)+((1−z)∗ht−1)
更新门 z z z 和重置门 r r r 的输出都是使用前一个隐藏状态 h t − 1 h_{t-1} ht−1 和当前输入 x t x_t xt 的组合计算得到的,Sigmoid
函数将这些函数的输出值调节到 0
和 1
之间。单元状态 c c c 是重置门 r r r 和输入 x t x_t xt 的函数输出,时刻 t t t 处的隐藏状态 h t h_t ht 是单元状态 c c c 和前一个隐藏状态 h t − 1 h_{t-1} ht−1 的函数输出。参数 w z w_z wz、 u z u_z uz、 w r w_r wr、 u r u_r ur、 w c w_c wc、 u c u_c uc 在训练过程中进行学习。
与 LSTM
类似,TensorFlow
也提供了 GRU
的实现,可以直接替换 RNN
单元。
2.3 Peephole LSTM
Peephole LSTM
是 LSTM
的一个变体。它在输入、遗忘和输出门上添加了窥视孔 (peephole
),使它们可以看到先前的单元状态 c t − 1 c_{t-1} ct−1。在 Peephole LSTM
中,使用以下方程从上一个时刻的隐藏状态 h t − 1 h_{t-1} ht−1 计算时刻 t t t 处的隐藏状态 h t h_t ht:
i = σ ( w i h t − 1 + u i x t + v i c t − 1 ) f = σ ( w f h t − 1 + u f x t + v f c t − 1 ) o = σ ( w o h t − 1 + u o x t + v o c t − 1 ) g = tanh w g h t − 1 + u g x t c t = ( f ∗ c t − 1 ) + ( g ∗ i ) h t = tanh ( c t ) ∗ o i=\sigma(w_ih_{t-1}+u_ix_t+v_ic_{t-1})\\ f=\sigma(w_fh_{t-1}+u_fx_t+v_fc_{t-1})\\ o=\sigma(w_oh_{t-1}+u_ox_t+v_oc_{t-1})\\ g=\text{tanh}w_gh_{t-1}+u_gx_t\\ c_t=(f\ast c_{t-1})+(g\ast i)\\ h_t=\text{tanh}(c_t)\ast o i=σ(wiht−1+uixt+vict−1)f=σ(wfht−1+ufxt+vfct−1)o=σ(woht−1+uoxt+voct−1)g=tanhwght−1+ugxtct=(f∗ct−1)+(g∗i)ht=tanh(ct)∗o
需要注意的是,与 LSTM
的方程唯一的区别在于,计算输入门 i i i、遗忘门 f f f 和输出门 o o o 输出时增加了 c t − 1 c_{t-1} ct−1 项。
在以上部分中,我们介绍了多个 RNN
单元变体,这些变体用于解决基本 RNN
单元的不足以提成性能。接下来,我们将介绍 RNN
网络的架构变体,这些变体旨在满足特定的任务需求。
3. RNN 变体
在本节中,我们将探讨一些基本 RNN
架构的变体,这些变体在特定任务场景中可以提供性能改进。需要注意的是,这些策略可以应用于不同类型的 RNN
单元,以及不同的 RNN
拓扑结构。
3.1 双向 RNN
我们已经知道,在任意给定的时刻 t t t,RNN
的输出依赖于所有先前时刻的输出。然而,输出也可能依赖于未来的输出,因为我们试图预测的词或短语可能依赖于整个句子的上下文,而不仅仅是之前的词。
双向 RNN
(Bidirectional RNN
, BiRNN
) 可以解决此问题,它本质上是两个堆叠在一起的 RNN
,一个从左到右读取输入,另一个从右到左读取输入。
每个时刻的输出基于这两个 RNN
的隐藏状态,双向 RNN
允许网络对序列的开头和结尾都给予同等重视,通常能带来性能的提升:
TensorFlow
通过双向封装层提供对双向 RNN
的支持,要使 RNN
层(如 SimpleRNN
或 LSTM
等)变为双向,只需将该层包装在此封装层中。由于在 BiLSTM
中左右 LSTM
中每对单元的输出是连接在一起的,它需要返回每个单元的输出。因此,将 return_sequences
设置为 True
(默认值为 False
,意味着只从 LSTM
的最后一个单元返回输出):
self.lstm = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(10, return_sequences=True, input_shape=(5, 10)))
3.2 状态 RNN
状态 RNN
(Stateful RNN
) 可以在训练期间跨批次保持状态。也就是说,为一批训练数据计算的隐藏状态将将会用作下一批训练数据的初始隐藏状态。这需要显式设置,因为默认情况下,TensorFlow
中的 RNN
是无状态的,并在每个批次后重置状态。将 RNN
设置为有状态意味着它可以在其训练序列中建立状态,甚至在进行预测时保持该状态。
使用状态 RNN
的优势包括网络尺寸较小且训练时间较短,缺点是我们需要负责使用反映数据周期性的批次大小来训练网络,并在每个 epoch
后重置状态。此外,在训练网络时不能打乱数据,因为数据呈现的顺序与状态网络相关。
要使用状态 RNN
层,将变量 stateful
设置为 True
。例如在生成文本任务中,使用由连续文本片段组成的数据进行训练,因此使用状态 RNN
意味着从前一个文本块生成的隐藏状态会被用于当前文本块。
4. RNN 拓扑结构
我们已经学习了如何组合多层感知器 (Multi-Layer Perceptron, MLP) 和卷积神经网络 (Convolutional Neural Network, CNN) 架构形成更复杂的网络,RNN
提供了另一种自由度,因为它们允许序列输入和输出。这意味着 RNN
单元可以以不同的方式排列,构建适合解决不同类型问题的网络。下图展示了 5
种不同的输入、隐藏层和输出配置。
一对一 (one-to-one
) 类型可以实现为一个简单的具有一个输入和一个输出的全连接网络。
一对多 (one-to-many
) 类型有一个输入并输出一个序列。这种网络可以用作从图像生成文本标签,其中训练数据集包含图像不同方面的简短文本描述,网络使用图像输入和表示图像标签的文本序列进行训练。
多对一 (many-to-one
) 类型则相反,以张量序列作为输入,输出单个张量。这种网络可以用作情感分析,它以文本块(如电影评论)作为输入,并输出文本情感类型。
多对多 (many-to-many
) 类型有两种形式。第一种更常见,称为 seq2seq
模型。在这种模型中,读取一个序列并生成代表输入序列的上下文向量,该向量用于生成输出序列。这种拓扑结构在机器翻译领域以及可以重构为机器翻译问题的问题中取得了巨大成功。第二种 many-to-many
类型具有与每个输入单元相对应的输出单元。这种类型的网络适用于输入和输出之间存在 1:1
对应关系的用例,如时间序列。这个模型与 seq2seq
模型的主要区别在于,在解码过程开始之前,输入不必完全被编码。
小结
循环神经网络 (Recurrent neural networks
, RNN
) ,RNN
是在文本输入中广泛使用的神经网络。RNN
非常灵活,已被用于解决诸如语音识别、语言建模、机器翻译、情感分析和图像字幕等问题。RNN
利用输入的序列特性,序列输入可以是文本、语音、时间序列以及任何其他元素的出现取决于其前面元素的序列。
在本节中,我们介绍了 RNN
及其变体,并学习如何使用 TensorFlow
进行实现。首先介绍了基本 RNN
单元的内部结构,以及它如何处理输入中的序列依赖关系。我们还将了解基本 RNN
单元的一些限制,并介绍两种基本 RNN
单元变体——长短期记忆 (Long Short Term Memory
, LSTM
) 和门控循环单元 (Gated Recurrent Unit
, GRU
),以及它们是如何克服基本 RNN
单元的限制的。然后,我们介绍了 RNN
层,RNN
层将 RNN
单元应用于每一时刻。RNN
可以被视为一个 RNN
单元图,每个单元对序列的连续元素执行相同的操作。我们还将进行一些简单的改进来提高性能,例如使 RNN
具有双向性或状态保留性。最后,介绍了一些标准的RNN
拓扑结构。
系列链接
TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(6)——回归分析详解
TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(8)——卷积神经网络
TensorFlow深度学习实战(9)——构建VGG模型实现图像分类
TensorFlow深度学习实战(10)——迁移学习详解
TensorFlow深度学习实战(11)——风格迁移详解
TensorFlow深度学习实战(12)——词嵌入技术详解