RNN 循环神经网络
普通的神经网络会有1个固定的输入维度,经过一系列的隐藏层计算得到一个固定的输出,如不同类别的得分/概率 向量。
循环神经网络,可以对序列进行建模,有多种不同的输入输出类型:
一对一、一对多、多对一、多对多等
基本概念
RNN 会有一个反复出现的小的循环核心单元。
RNN在每个time step进行如下的计算:
- 读取输入-> 更新隐藏层-> 基于隐藏层计算得到输出
我们在每个 time step 都使用同样的方程和相同的参数进行计算
- x t x_t xt 是某时刻输入的向量
- h t − 1 h_{t-1} ht−1 是该时刻之前的隐藏状态
- f W f_W fW是参数为W的函数
- h t h_t ht是更新后的隐藏状态
这样,在向前传播的时候,一个结构不断循环。
vanila (朴素)RNN
计算图
- 初始隐藏层为 h 0 h_0 h0
- 在 t=1时刻有输入 x1,将 h 0 、 x 1 h_0、x_1 h0、x1 带入函数 f W f_W fW得到 h 1 h_1 h1来更新隐藏层
- 以此类推得到 x t x_t xt时刻的隐藏状态 h t h_t ht
- 计算隐藏层的时候,每一步都是用相同的W参数,函数 f W f_W fW也是相同的。
如果不是一一对应的多对多,可以看成多对一和一对多的组合。
首先输入一个不定长的 x 将序列编码成一个单独的向量,然后作为输入,输入到一对多的模型中,得到输出序列。
反向传播
计算梯度时,遍历整个序列计算梯度,时间花费巨大。
截断反向传播 Truncated Backpropagation
前向传播时,不再使用整个序列计算损失,二十使用序列的一个块,计算出损失,然后进行反向传播计算梯度。
RNN 梯度消失 梯度爆炸
-
隐藏层
s t = σ ( U x t + W s t − 1 + b 1 ) s_t = \sigma(Ux_t + Ws_{t-1} + b_1) st=σ(Uxt+Wst−1+b1) -
输出状态
o t = g ( V s t + b 2 ) o_t = g(V s_t + b2) ot=g(Vst+b2) -
Loss 计算
L = ∑ t L t = ∑ t L o s s ( o t , y t ) L = \sum_t L_t = \sum_t Loss(o_t,y_t) L=t∑Lt=t∑Loss(ot,yt)
-
反向传播过程
t=3时刻,计算损失函数
时间序列越长,出现连乘的部分越集中。
h
j
h_j
hj表示中间隐藏层
朴素RNN的梯度流
h0的梯度求导涉及许多W相乘
- 梯度爆炸所指的是一个网络的梯度无限大。
- 梯度消失所指就是一个网络的梯度无限接近于0 。
- 梯度爆炸和消失不是RNN的“专利”,在其他的前馈网络中也会出现,当网络的层数过大,或者选择了不恰当的激活函数都会导致梯度问题在前馈网络中的出现。但是在RNN中尤为的明显。
当梯度爆炸的时候,可以将梯度截断。
当梯度消失,尝试寻求新的RNN结构来解决。
多层RNN
多层RNN ,隐藏层有3层
Long Short Term Memory LSTM
LSTM 结构相比朴素RNN更加复杂,LSTM 在每个时间步都维持两个状态, h t 、 c t h_t、c_t ht、ct:
- ht 和普通RNN一样,是RNN的隐藏层
- 单元状态向量Ct,是保留在LSTM内部的隐藏状态,不会完全暴漏到外部去。
首先计算四个门的值
-
i:input gate 便是有多少内容背心写入到单元状态
-
f:forget gate 表示对之前单元状态的以往程度
-
o:output gate 表示单元状态输出多少给隐藏态
-
g:gate gate 控制写入导单元状态的信息
-
f是对之前的单元状态的遗忘,如果是0 全部遗忘,如果是1 就全部保留,那个圆圈加点的符号表示逐元素相乘
-
i和g共同控制写入单元状态向量的信息,i在0~1,g在 -1~1之间,每个实践不,单元状态向量的每个元素最大自增1,最小自减1
-
这样 ct可以看成是对[-1,1] 的按时间步计数。然后通过tanh() 将这个计数压缩到 [0,1] 范围,然后 o 来控制将多少单元状态的信息输出给隐状态 ht
更新梯度时的梯度流: