本周开始,我将一周分享和总结三篇关于自然语言处理方面的论文及其开源代码(如果有的话),以期在三个月后的校招面试中能招架住面试官的各种提问。
本篇论文中了
传统
RNN
以及
LSTM
、
GRU
缺陷
传统的
RNN 由于梯度消散或者梯度爆炸的原因,导致其无法很好的应对步长较长的输入。
ht=σ(Wxt+Uht−1+b)
这里需要注意RNN 共享一组参数W、U、b ,也就是不同的time_step 、样本,所对应的W、U、b 是相同的,极大的减小了需要训练的和预估的参数。shape 分析(不考虑batch_size ):
M 表示input x 的特征数或者其经过word embedding 后的输入宽度;N 表示一个cell 内神经元个数。
ht :shape[N] ;W :shape[N,M] ;xt :shape[M] ;U :shape[N,N] ;ht−1 :shape[N] ;b :shape[N]
我们以损失函数对参数求导,然后在反向更新参数,然而这个求导的过程是一个一层一层累积的过程,随着层数的增加的,梯度消散或爆炸的现象也将越来越严重。具体的数学公式推导请看 RNN,LSTM数学推导LSTM 在一定程度上解决了梯度消散或爆炸的现象,使得能较好的处理较长的序列,但是由于使用了sigmoid或tanh 等saturate 激活函数,使得梯度在层之间的消散或者爆炸现象较严重。我们知道
sigmoid 、tanh 等saturate 激活函数会产生梯度消散或爆炸的现象,那么为什么我们在LSTM 等网络中还使用这种激活函数呢?
我个人的理解是:在LSTM中,激活函数并不是仅仅用来激活,刷选过滤信息,激活函数还有一个更重要的目的要实现,就是要使得记忆细胞在沿着传送带不断传送之前的记忆时,还需要保证信息不会膨胀,要保证信息量在一定范围内。那么这就必须使用sigmoid函数作为激活函数,reLu函数做不到这一点。当然有论文实验(Path\-normalized optimization of recurrent neural networks with relu activations )证明可以使用RELU 作为激活函数,具体效果如何可细看这篇论文,这里不再深究。正是由于这个原因使得我们很少见到
RNN 或LSTM 等像CNN 那样堆叠多层的模型,在CNN 中,我们可以利用relu 、resNet 等方法使得模型可以堆叠很深很深,也已有论文(Exploring the depths of recurrent neural networks with stochastic residual learning )实验证明,在深层的RNN 、LSTM 的网络中搭建resNet ,其实验效果并无多大提高。可解释性差,我们由上面的
RNN 公式,其中U∗ht−1 是矩阵乘法,其中ht−1 表示上一个每个神经元的输出,ht 表示当前时刻每个神经元的输出,由公式可知,上一个时刻的神剧原与当前时刻的神经元是交织纠缠在一起的,也就是在RNN 、LSTM 中相同层内的神经元是相互纠缠在一起,很难独立解释他们的行为。
好了,作者不断在论文中讲传统
IndRNN
首先看看
对,就是这么简单,就是将
我们从上面的
这里面
梯度在反向回传的时候,可以被调整,使其更有效的处理梯度消散或爆炸现象。是不是很迷茫?一脸懵逼?作者说可以被调整,然后就有效?什么鬼?来来,走一遍数学公式验证下。
我们假设在第
T 步,需要优化的目标为Jn ,那么当梯度回传到第t 步时,其计算结果如下:
∂Jn∂hn,t=∂Jn∂hn,T∂hn,T∂hn,t=∂Jn∂hn,T∏k=tT−1∂hn,k+1∂hn,k=∂Jn∂hn,T∏k=tT−1σ′n,k+1un=∂Jn∂hn,TuT−tn∏k=tT−1σ′n,k+1
由上面的推导结果可知,梯度回传结果只与u 和激活函数的导数有关,激活函数的导数在一定范围内改变(例如大部分激活函数,sigmoid、tanh、relu 导数只在(0,1)),我们可以调整的只有u (本身u就是模型参数),这就好办了,这就意味着只要调整调整u 即可控制和调整反向传播时梯度变化。我们可以轻而易举的将
uT−tn∏T−1k=tσ′n,k+1 调整至适当的范围内。
举例来说,我们希望梯度在反向传播时,不管梯度传递到哪一步,其获取的最小的有效梯度一定要大于ϵ ,那么我们在定义U 矩阵时,可以使:∣∣un∣∣∈ϵ∏k=tT−1σ′n,k+1‾‾‾‾‾‾‾‾‾‾‾‾√T−t
更进一步的说,上面因为定义了最小值,可以防止梯度消散,那么怎么防止梯度爆炸呢?同理嘛,可以定义:
∣∣un∣∣∈⎡⎣⎢⎢ϵ∏k=tT−1σ′n,k+1‾‾‾‾‾‾‾‾‾‾‾‾√T−t,γ∏k=tT−1σ′n,k+1‾‾‾‾‾‾‾‾‾‾‾‾√T−t⎤⎦⎥⎥
这样就定义了梯度回传时的最大值和最小值了。
有人可能要问了,上公式中的∏k=tT−1σ′n,k+1 是不知道的?这个问题。。。你想想sigmoid、tanh、relu 不都是在一定范围内变化吗?例如relu 导数不是0就是1,当我们选用relu 时,其:
∣∣un∣∣∈[0,γ√T−t]
由上面的IndRNN 数学公式可知,当un=0 时表示该神经元有输入xt 而无记忆信息输入。这是一个学习的过程,不同的神经元有不同长度的记忆信息保存。不过这一步我觉得可以使用Leaky Relu ,这样就是避免了传递的梯度为0了。在开源的代码中,他是建议矩阵u 最大值设置为pow(2,1/timesteps) 。IndRNN 能保存更长的记忆,实验表面,IndRNN 能处理步长超过5000 的序列,而LSTM 最多只能处理步长1000 的序列。关于这一点论文中并无过多证明。IndRNN 可以更好的与non saturate 函数结合起来工作,例如relu ,并且更具鲁棒性。论文中对比了传统RNN 和IndRNN 反向传导的数学公式,得出传统RNN 在反传梯度时变化更大,不容易控制,稳定性差,而IndRNN 的梯度只是与u 有关,波动性不大。IndRNN 可以进行多层堆叠,并且可以有效的利用resNet 机制,使得可以搭建更深的网络。关于这一点,论文花了一部分篇幅证明了传统的两层RNN ,注意激活函数必须是线性的,可以看做是两层IndRNN 的一种特例,但是这和可以多层堆叠貌似没啥关系。然后又在理论上说,对输入做个卷积操作,加batchnormlization、resNet ,IndRNN 就可以搭建的更深?具体操作可以参考论文中的语言模型的实验,不过我个人看来,像这种序列模型,搭建更深没啥意义,而在图像上深层CNN 模型已经表现够好了。- 每层中各个神经元相互独立,解释性强,这点上面数学已经证明,而不同层之间的神经元才有所交织。因为下层的神经元的输出
ht 作为上层神经元的输入Xt 。