这周在看循环神经网络,发现一个博客,里面的推导过程极其详细,借此记录重点
强烈介意手推一遍,虽然可能会花一点时间,但便于理清思路。
语言模型
RNN是在自然语言处理领域中最先被用起来的,比如,RNN可以作为语言模型来建模。
什么是语言模型?
语言模型:给定一个一句话前面的部分,预测接下来最有可能的一个词是什么。
语言模型可以用在语音转文本(STT)上,也可以用在图像到文本的识别中(OCR)。
使用RNN之前,语言模型主要采用N-Gram,即先对句子切词,再在语料库中搜索前n个词进行预测,这样想法没有实用性,因为根本没有用到有用的信息,并且该模型还会占用海量的存储空间。
所以,RNN出现,理论上RNN可以往前看(往后看)任意多个词。
循环神经网络
基本神经网络
如上图左,一个简单的循环神经网络由一个输入层、一个隐藏层和一个输出层组成。
其中, x x 是一个向量,代表输入层的值;是一个向量,代表隐藏层的值; o o 是一个向量,代表输出层的值。
是输入层到隐藏层的权重矩阵, V V 是隐藏层到输出层的权重矩阵,权重矩阵是隐藏层上一次的值作为这一次的输入的权重。循环神经网络与普通的全连接神经网络不同的地方也就在于 W W 。
如上图右,可表示循环神经网络的计算方式:
其中,式1是输出层的计算公式,输出层是一个全连接层,即每一个节点都与隐藏层的每个节点相连,g代表激活函数, V V 是输出层的权重矩阵。
式2是隐藏层的计算公式,它是一个循环层,f是激活函数,是输入 x x 的权重矩阵,是上次值 st−1 s t − 1 作为这次输入的权重矩阵。
双向循环神经网络
对于语言模型来说,很多时候光看前面的词是不够的,还需要看后面的词。普通的基本循环神经网络对此无法建模,因此,我们需要双向循环神经网络。
从上图可知,双向循环神经网络的隐藏层要保存两个值,一个
A
A
参与正向计算,另一个值参与反向计算。最后的输出值
y2
y
2
取决于
A2
A
2
和
A′2
A
2
′
。仿照式1和试2,双向循环神经网络的计算方法如下:
可以看出:正向计算时,隐藏层的值 st s t 与 st−1 s t − 1 有关;反向计算时,隐藏层的值 s′t s t ′ 和 s′t−1 s t − 1 ′ 有关。正向计算和反向计算 不共享权重,也就是说 U U 和、 W W 和、 V V 和都是不同的权重矩阵。
深度循环神经网络
之前介绍的RNN都是只有一个隐藏层,当堆叠两个以上隐藏层时,就得到了深度循环神经网络
把第i个隐藏层的值表示为
s(i)t
s
t
(
i
)
、
s′(i)t
s
t
′
(
i
)
,则深度循环神经网络的计算方式可以表示为:
循环神经网络的训练
循环神经网络的训练算法:BPTT
BPTT算法是针对循环层的训练算法,基本原理和BP算法一样,包含三个步骤:
前向计算每个神经元的输出值;
反向计算每个神经元的误差项 δj δ j 值,它是误差函数E对神经元j的加权输入 netj n e t j 的偏导数;
计算每个权重的梯度。
最后再用随机梯度下降算法更新权重。
循环层如下图所示:
1. 前向计算
使用式2对循环层进行前向计算:
上式中, st s t 、 xt x t 、 st−1 s t − 1 都是向量,U、V是矩阵,向量的下标表示时刻。
2. 误差项的计算
BTPP算法将第 l l 层的t时刻的误差项值沿两个方向传播,一个方向是传递到上一层网络,得到 δl−1t δ t l − 1 值,这部分只与U有关;另一方向是沿时间线传递到初始 t1 t 1 时刻,得到 δl1 δ 1 l 值,这部分只与W有关。
我们用向量
nett
n
e
t
t
表示神经元在t时刻的加权输入,因为:
因此(详细推导此处略过,详情见链接):
上式描述了将δ沿时间往前传递一个时刻的规律,根据这个规律,可以求得任意时刻k的误差项 δk δ k :
式3是将误差项沿时间反向传播的算法。
循环层将误差项反向传递到上一层网络,与普通的全连接层完全一样。
式4就是将误差项传递到上一层的算法。
3. 权重梯度的计算
首先,我们计算误差函数E对权重矩阵W的梯度 ∂E∂W ∂ E ∂ W .
上图展示了前两步已经计算得到的值,包括每个时刻t循环层的输出值 st s t 以及误差项 δt δ t 。
梯度计算算法:只要知道了任意一个时刻的误差项
δt
δ
t
,以及上一个时刻循环层的输出值
st−1
s
t
−
1
,就可以按照下面的公式求出权重矩阵在t时刻的梯度
∇WtE
∇
W
t
E
:
我们求得了权重矩阵W在t时刻的梯度 ∇WtE ∇ W t E ,最终的梯度 ∇WE ∇ W E 是各个时刻的梯度 之和(至于为什么是“和”,详细推导见链接):
式6就是计算循环层权重矩阵W的梯度的公式。
RNN的梯度爆炸和消失问题
不幸的是,前面提到的几种RNNs都不能很好的处理较长的序列。原因是RNN在训练中很容易发生梯度爆炸和梯度消失,这导致训练梯度不能在较长序列中一直传递下去,从而使RNN无法捕捉到长距离的影响。(具体原因见链接)
处理梯度爆炸:设置一个梯度阈值,当梯度超过这个阈值时可以直接截取。
处理梯度消失:
合理的初始化权重值。初始化权重,使每个神经元尽可能不要取极大值或极小值,以躲开梯度消失的区域。
使用ReLU代替Sigmoid和tanh作为激活函数。
使用其他结构的RNNs,如长短时记忆网络(LTSM)和Gated Recurrent Unit(GRU)。