笔者最近对RNN网络进行知识补漏,现将最近了解到的内容整理如下,如有理解不准确的部分,欢迎指正。
说起RNN的机制,一般RNN的隐藏单元更新函数为:
其中分别为当前时刻的输入数据
和上一时刻隐藏单元信息
的可学习权重系数。不同于一般CNN网络的神经元更新
,当前隐藏单元信息只与当前输入有关,而在RNN的更新过程中,当前时刻之前的各个时刻信息被包含在上一时刻的隐藏单元信息中,一同作用当前时刻的隐藏单元更新过程,当前时刻的隐藏单元由当前时刻输入数据和上一时刻隐藏单元的信息共同决定。
一般的RNN结构(其它形式的结构应用见文末补充内容1)每层RNN卷积层都可以看成是在时间上展开的一个卷积序列,如图:
值得注意的是,RNN的上述展开形式,每个隐藏单元h的脚标表示的是不同时刻,展开来写:
(1)
这里的都是同一个参数,即参数共享。前向过程比较好理解,现在我们来看RNN采用的反向传播,是随时间反向传播back-propagation through time(BPTT),其实本质还是BP算法,只不过RNN处理时间序列数据,所以要基于时间反向传播,故叫随时间反向传播。此处以
,来看反向传播过程,首先明确待学习的参数为
,因此以
为例,求
对
的偏导,应用链式法则得到:
根据规律可得,上述各公式可以统一为
可以观察到,在某个时刻对的偏导数,需要追溯这个时刻之前所有时刻的信息,这还仅仅是一个时刻的偏导数,上面说过损失也是会累加的,那么整个损失函数对W和U的偏导数将会非常繁琐。整体的偏导公式就是将其按时刻将之前的所有时刻再加起来:
从上述的表达公式可以看到
其实就是含有激活函数
的乘子,因此在
中
的累乘等价于会导致激活函数导数的累乘,而RNN使用的sigmod和tanh激活函数都属于饱和激活函数(详情解释见文末补充内容2),sigmoid函数的导数范围是(0,0.25],tanh函数的导数范围是(0,1],他们的导数最大都不大于1。这就会导致一个问题,在上面式子累乘的过程中,如果取sigmoid函数作为激活函数的话,那么必然是一堆小数在做乘法,结果就是越乘越小。随着时间序列的不断深入,小数的累乘就会导致梯度越来越小直到接近于0,这就是“梯度消失“现象。ReLU激活函数的左侧导数为0,右侧导数恒为1,这就避免了“梯度消失“的发生。但恒为1的导数容易导致“梯度爆炸“。
补充内容1. 其它形式的RNN结构应用
RNN结构,在实际中这一种结构也可以有不同的应用形式,例如我们输入为一串文字,输出为分类类别,那么输出就不需要一个序列,只需要单个输出,但有时候还需要单输入但是输出为序列的情况。两种情况如图:
补充内容2. 饱和和非饱和的激活函数
当有激活函数,其导数为
时:
- 饱和激活函数(saturated activation function):
- 当
,称其为右饱和激活函数;
- 当
,称其为左饱和激活函数;
- 当
,称其为饱和激活函数。
常见的饱和激活函数sigmod, tanh
- 非饱和激活函数(non-saturated activation function):
不满足上述条件的称为不饱和激活函数,常见的饱和激活函数Relu
参考: