url:http://blog.csdn.net/sysstc/article/details/75333008
Training RNN——BPTT
由于RNN和时间序列有关,因此我们不能通过Backpropagation来调参,我们使用的是Backpropagation through time(BPTT)回顾Backpropagation
【RNN训练方法介绍-BPTT】
文章图片
文章图片
Backpropagation through Time(BPTT)
我们可以将RNN变成如下形式:
文章图片
参照之前的BP我们发现,反向传播其实就是一个梯度* 矩阵 * 激活函数的微分(放大器)。由于an-1和xn同时会影响到an,而an-1又会被an-2和xn-1影响,并且依次传递下去,a1的值会被x1和memory cell initial影响。因此,我们可以把RNN看成一个非常深的DNN,将input看成:Init,x1,x2,…,xn,output是yn,也就是如果n=100,那么就有100个hidden layer。
- 如何计算Cn这项的gradient呢
BPTT同样等于Backward pass + forward pass,forward pass 可以直接当做是一个DNN来计算,而backward pass可以看成如下所示,通过一个hidden layer,就相当于乘以一个个的放大器(activation function)
文章图片
文章图片
如何更新参数呢,我们看到上面黄色的箭头都是相同的weights,而上面蓝色的箭头也都是相同的weights。因此我们根据如下方式修改。
文章图片
- 如何计算所有的gradient呢?其实也是一个forward pass和一个backward pass
文章图片
- RNN的error surface(误差曲面)是比较崎岖的,有些地方斜率很大,有些地方斜率很小。如
文章图片
- RNN中gradient vanish产生的原因和DNN gradient vanish产生的原因不一样。
- DNN:gradient vanish是因为backward pass时,每经过一层都要经历一个activation function的微分,那这时如果我们使用的activation function是sigmoid,由于sigmoid的微分最大值为1/4,那么error signal就会越来越小,最后可能会出现梯度消失的情况。我们之前提到的解决方式是将activation function由sigmoid改成relu。
- RNN:
- 从一个小案例分析:参考下面图,我们要计算gradient,下面是一个RNN,Input都是1,output都是1,hidden layer 里面就一个神经元,这里我们将hidden layer设置为一个linear。那么由于是一个linear,是不是我们就不会出现gradient vanish的情况呢?答案是否定的:
文章图片
我们发现w的不同,yn变化忽大忽小。这样就会变得非常难处理。就式子和函数图像来分析原因:
文章图片
这种情况就造成我们在算gradient的时候,大多都是一些极端值。
那么从这个角度来看我们发现如果你这时候将activation function设置为sigmoid或tanh,这种微分值小于1的activation function,反而能在某种程度上保护rnn,而用relu则不会削减这些大爆炸的情况。所以在处理RNN的时候还是应该采用tanh或者sigmoid - 从一般情况来分析,今天为了简化分析,我们将activation function都认为是linear activation function,底下的error signal 没有考虑activation function,如果error signal对应到的Wn-1是小于1的话,那么值就会变得很小,如果error signal对应到的Wn-1大于1的话,那么值就会变得很大。
文章图片
- 从一个小案例分析:参考下面图,我们要计算gradient,下面是一个RNN,Input都是1,output都是1,hidden layer 里面就一个神经元,这里我们将hidden layer设置为一个linear。那么由于是一个linear,是不是我们就不会出现gradient vanish的情况呢?答案是否定的:
- RNN中gradient vanish的解决方法:
- Clipped Gradient:设置一个threshold,clip(x,min,max)
- NAG:Momentum进化版。
- Momentum是一个模范物体运动的方法,update方向取决于所在位置的Gradient的反方向+上次的movement,这样就可能会照成数值波动。
- NAG的update方向取决于从现在所在的位置沿着movement再走一步所在的Gradient的反方向+上一次的movement。这样可能会避免产生震荡的情形
文章图片
- RMSProp:Adagrad的进化版
- Adagrad:除去这个参数过去所有算出来的gradient的平方和再开根号(即对二次微分的估算)。这样就可以动态调整learning rate
- RMSProp:
过去的gradient会乘上α(0<α<1),那么越过去的gradient我们考虑的权重就会更小,这样二次微分对同一个参数也会产生变化。
文章图片
- LSTM网络:
文章图片
- LSTM的BPTT过程(考虑gradient):
- LSTM的forward pass过程:
- 只需要把data带进去就可以求每个neural的output
- LSTM的backward pass过程:
- 遇到了一个”+”,我们可以把这个看成一个activation function。input:a/b,output:a+b,微分值为1。
- 遇到了一个”x”,我们也把这个看成一个activation function。input:a/b,output:axb,微分值为b/a,底下图片上的点乘代表的是element-wise。
文章图片
如果我们今天从yt+1做bptt,假设forget gate是开启状态,那么我们发现,从yt+1开始的error signal在通过灰色matrix时会乘以一个W的transposition,在通过activation function时可能会乘以一个小于1的数字之外,error signal就是一路畅行无阻的,就会一路保持constant的error signal,这就是Constant Error Carrousel(CEC)。这样error signal一路保持constant的值的好处有什么呢?如果今天你要update黄色箭头里的element,那么因为红色箭头不会随时间衰减太多,所以蓝色的值也不会太小,那么拿来update黄色箭头的error signal不会太小。
文章图片
因此LSTM可以解决gradient vanish的问题,但LSTM不能处理gradient explode的问题因为error signal不只走蓝色的箭头,还有可能走绿色的箭头,绿色的箭头再走到蓝色箭头的部分就会一直乘以一个W的transposition,如果W的transposition是小的则没关系,因为error signal是比较大的(之前提到过,在error signal的流动过程中它减小的很少)。但如果W的transposition是大的,这时候不断的乘以W的transposition,值就会变得越来越大,就可能会导致gradient explode的情况。
文章图片
- LSTM的forward pass过程:
- RNN和LSTM的差异:对待memory的方式不同。
- 对于RNN,每一个step我们都会把hidden Layer的output写到memory里面去,所以memory里面的值每次都会被完全修正,过去的东西其实一点都没有存留下来。这就会导致当你修改模型中某个参数的时候,可能会造成很大的变化,也有可能没有变化。
- 对于LSTM,如果没有forget gate,那么我们过去得memory都会保存下来,因为我们用的是”+”。如果我们的forget gate没有被开启,那么这个memory就会永远的存在。这样如果我们的memory都会一直留下来,那么在修改某个参数时造成某个改变时,这个改变就不会消失,这样我们的gradient就不会消失,这样就可以保证我们的gradient不会特别小。但无法保证gradient不会explode。
文章图片
Better Initialization
- 产生gradient explorde/vanish的problem是因为我们不断乘上一个Weight matrix的transposition。如果某一个vector正好是weight matrix的identity value是1的话,这件事情就不会发生,那么我们对RNN进行变形,我们让hiddenlayer和hiddenlayer相接的matrix用indentity matrix,然后用Relu作为activation function,这样activation function的影响就可以不计。
红色的就是initialized with identity matrix+ReLU
文章图片
在training RNN的时候可能会遇到Gradient vanish和Gradient explode的问题。
这里的解决方法:
- 设置一个threshold(min,max)
- 优化技术
- NAG
- RMSprop
- LSTM(或者其他变形)
- 更好的初始化,hidden layer之间的weight初始化用identity matrix,activation function用ReLU.
推荐阅读
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- paddle|动手从头实现LSTM
- pytorch|使用pytorch从头实现多层LSTM
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- pytorch|YOLOX 阅读笔记
- 前沿论文|论文精读(Neural Architecture Search without Training)
- 联邦学习|【阅读笔记】Towards Efficient and Privacy-preserving Federated Deep Learning
- OpenCV|OpenCV-Python实战(18)——深度学习简介与入门示例
- 深度学习|深度学习笔记总结
- 《繁凡的深度学习笔记》|一文绝对让你完全弄懂信息熵、相对熵、交叉熵的意义《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(中)(DL笔记整理