MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的深度学习
循环神经网络方面的知识。
???? 导读
简单来说吧,循环神经网络(Recurrent Neural Network)也就是我们常见的RNN了,它是用来构建序列化模型的一种主流深度学习模型,我们传统的前馈神经网络一般的输入都是定长的向量,无法处理会变长的序列信息,有些同学会说我把它转换成定长向量不就好了吗?但其实不然,即便转换了,模型也很难去捕捉到序列中的长距离依赖关系。
因此,这里就提出了RNN的方法,RNN通过将神经元串行起来处理序列化的数据,由于每个神经元能用它的内部变量保存之前输入的序列信息,因此整个序列就可以被进行抽象表示,并据此进行分类or生成新序列。所以这个RNN也经常会被应用在机器翻译、序列标注、图像描述、推荐系统、AI机器人等等。
???? Index
-
RNN与CNN的区别与联系
-
RNN存在梯度消失or梯度爆炸?
-
重点深入了解下LSTM
-
重点深入了解下Seq2Seq
???? RNN与CNN的区别与联系
在我们处理文本数据的时候,通过会做的操作就是把语料所对应的的TF-IDF向量作为输入,其中TF-IDF向量的维度是词汇表的大小。
TF-IDF: 一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
传统做法,就是使用CNN接收TF-IDF向量作为特征输入,然后通过滑动窗口加池化的方法将原先的输入转换成一个固定长度的向量表示,虽然这样子也会捕捉到局部的特征,但长距离单词之间的依赖信息就会丢失了。
卷积神经网络(Convolutional Neural Network,CNN),它也是属于前馈神经网络的一种,其特点是每层的神经元节点只响应前一层局部区域范围内的神经元(全连接网络中每个神经元节点则是响应前一层的全部节点)。
RNN就可以避免这种情况,它可以很好地处理文本数据变长并且有序的输入序列,简单来说它是模拟了一个人在阅读文章的情景,从开始读到最后读完,并且拥有”记忆“能力(把前面阅读到的有用信息编码到状态变量里去)。
☠️ RNN存在梯度消失or梯度爆炸?
梯度消失(Gradient Vanishing),也就是梯度的反向传播过程中,后层的梯度以连乘方式叠加到前层,而一般我们的神经网络的**函数都是用的Sigmoid函数,它具有饱和特征,即在输入达到一定值的时候,输出就几乎不会发生明显改变了,而后层的误差梯度反传回前层的时候,几乎就会衰减为0,因此前层的参数无法得到有效的学习。
梯度爆炸则是相反,大于1的值不断连乘带来一个很大的误差返回。
Sigmoid函数就是Logistic函数,其数学表达式、对应函数图像、导函数和导函数图像为:
可以看出,Sigmoid**函数在定义域上是单调递增的,越靠近两端变化越平缓,从导数图像可以看出,Sigmoid函数的导数取值范围在0-0.25之间,如果我们初始化的网络权值∣w∣小于1(一般也是这么操作),随着层数不断增多,每次连乘后逐渐变小,梯度就逐渐消失了。
同理,梯度爆炸也是类似,当我们的初始化的网络权值过大,导致 ∣σ′(z)w∣>1,不断连乘后就会得到一个很大的值了。
✅ 梯度消失和爆炸会带来什么影响?
最直观的解释就是,当在模型训练过程中出现了梯度消失,接近输出层的隐含层的梯度是正常的,所以权值更新的值也是正常的,但是越往回传递,出现了梯度消失的问题,这个时候输入层附近的隐含层的权值更新就会缓慢甚至停滞,所以就相当于前面的几个隐含层是”形同虚设“,深度网络其实就不再”深度“了,而可能只是后面几个隐含层构成的浅层网络。
✅ 解决方法:
对于这种常见的问题,当然解决办法也是很常见的了,下面罗列几条:
1)更换**函数
比如几种常见的**函数,对于避免上述的问题很有效。
ReLU:使得我们的**函数导数为1
LeakyReLU:ReLU的优化,同时解决了ReLu中0区间带来的影响
2)使用ResNet残差结构
其实为了解决梯度消失和爆炸问题,BN(Batch Normalization)结构也可以顺利解决,BN层对每层的输出做归一化,这样梯度在反向层层传递后仍可以保持大小稳定,不会出现过小或过大的问题,但BN在深度不断增大后会出现一个问题:Degradation Problem(准确率下降问题)。这个问题在我们的网络层级达到一定深度的时候就会出现,准确率饱和,然后迅速下降,这个问题不是由于过拟合或是梯度问题导致的,而是由于网络结构太过于复杂导致的,换句话说就是如果不加约束的放羊式训练很难达到理想的准确率的。
ResNet的提出就是为了解决这个问题的。
3)预训练加微调
Step1:pre-training(预训练)
此方法来自Hinton在2006年发表的一篇论文,Hinton为了解决梯度的问题,提出采取无监督逐层训练方法,其基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出作为输入,而本层隐节点的输出作为下一层隐节点的输入,此过程就是逐层“预训练”(pre-training);
Step2:fine-tunning(微调)
在预训练完成后,再对整个网络进行“微调”(fine-tunning)。Hinton在训练深度信念网络(Deep Belief Networks中,使用了这个方法,在各层预训练完成后,再利用BP算法对整个网络进行训练。此思想相当于是先寻找局部最优,然后整合起来寻找全局最优。
4)梯度剪切、权重正则化
梯度剪切这个主要是针对梯度爆炸而设计的解决方案,其核心思想就是设置一个梯度剪切的阈值,在更新梯度的时候对超出阈值的限制为该阈值,防止梯度爆炸。
权重正则化也是为了解决梯度爆炸问题而提出的,常见的就是L1、L2正则化,在各个深度框架中都有对应的API可以使用正则化,正则化是通过对网络权重做正则限制过拟合,如下面的Loss Function:
其中α指的是正则化系数,当发生梯度爆炸的时候,权重的范数就会变得很大,通过正则项则可以防止部分梯度爆炸的发生。
5)LSTM
LSTM全称是长短期记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要原因在于LSTM内部复杂的“门”(gates),如下图,LSTM通过它内部的“门”可以接下来更新的时候“记住”前几次训练的”残留记忆“,因此,经常用于生成文本中。目前也有基于CNN的LSTM,感兴趣的可以尝试一下。
???? 重点深入了解下LSTM
长短期记忆网络(long-short term memory networks,LSTM)是循环神经网络的最知名和成功的扩展,可以对有价值的信息进行长期记忆,从而减小循环神经网络的学习难度,因此在语音识别、语言建模、机器翻译、命名实体识别、图像描述文本生成等问题中有着广泛应用。
✅ LSTM如何实现长期记忆功能?
还是上面的图,与传统循环神经网络相似,但是对内部结构进行精心设计,加入了输入门、遗忘门以及输出门,还有一个内部记忆单元。
1)输入门控制当前计算的新状况以多大程度更新到记忆单元中;
2)遗忘门控制前一步记忆单元中的信息有多大程度被遗忘;
3)输出门控制当前的输出有多大程度上取决于当前的以及单元。
进一步解释,也就是说LSTM的状态转移不一定全部由**函数的计算结果,还得依赖于输入门与遗忘门来共同控制,如:
在一个训练好的网络中,当输入的序列中没有重要的信息,LSTM的遗忘门的值会接近于1,输入门的值接近于0,此时过去的记忆仍会被保留,从而实现了长期记忆功能;但如果输入的序列中出现了重要信息的时候,LSTM就会把它存入记忆中,此时输入门的值会更新为1,而遗忘门的值会接近于0,这样子旧的记忆就会被遗忘,新的信息就会被记忆。
✅ LSTM用的是什么**函数?
在LSTM中,遗忘门、输入门和输出门使用SIgmoid函数作为**函数,在生成候选记忆时候,使用双曲正切函数Tanh作为**函数。因为Sigmoid函数的输出值在0~1之间,符合门控的物理定理,即输入较大or较小的时候其输出会非常接近1or0,从而保证了门的开关。在生成候选记忆的时候,使用Tanh函数的原因是因为其取值范围为-1~1之间,与大多数场景下特征分布是0中心吻合,同时Tanh函数在输入为0附近相比于Sigmoid函数有更大的梯度,通常使得模型收敛更快。
???? 重点深入了解下Seq2Seq
Seq2Seq,全称是Sequence to Sequence模型,大致是意思就是将一个序列信号通过编码和解码生成一个新的序列信息,通过会用于机器翻译、语音识别、自动对话等任务。它的核心思想就是通过深度神经网络,将一个作为输入的序列映射为一个作为输出的序列,这一过程由编码输入和编码输出两个环节构成,在经典的实现中,编码器和解码器各有一个循环神经网络来构成,既可以是传统循环神经网络结构,也可以是LSTM、门控循环单元等。
这里有一个简单形象的例子:
在一次期末考试,我们将需要复习的知识经过复习(加工),形成了知识体系(结构),这就是编码过程。在考试的时候,将高度抽象的知识体系应用到具体的问题中去求解,这就是解码过程。
对于学霸,在复习过程就可以构建成一个比较强大的网络,可以对很长(很难很久远)的信息进行抽象理解,加工内化为编码向量,在考试中从容应答问题。
对于一般人,很难记忆长距离、高难度的信息,一般都只好”临时抱佛脚“,编码很短期的序列信号,考试时候就听天由命,能答多少就写多少。
???? Seq2Seq的核心在于解码
Seq2Seq的核心在于解码部分,大量的改进也是在解码环节衍生的,其最基本的解码方法就是贪心法,即选取一种度量标准后,每次都在当前状态下选择最佳的一个结果,直到结束。这种方法有一个最大的弊端就是面对复杂的问题的时候,很难得到最优解。
那么,这里有一个改良的算法,叫做集束搜索,它是一个启发式算法,该方法会保存beamsize个当前的较优选择,然后解码时每一步根据保存的选择进行下一步扩展和排序,接着继续选择前beamsize个进行保存,循环迭代,直到结束时选择最佳的一个作为解码的结果。
???? 解码的另一重要改进:注意力机制
Attention Mechanism的提出源自于一个问题。在实际的使用中,随着输入序列的增长,模型的性能发生了显著下降,因为编码时输入序列的全部信息被压缩到了一个向量表示中,随着序列增长,句子越前面的词的信息丢失就越严重。
引入注意力机制就是为了解决上述问题的,在注意力机制中,仍可以用普通的循环神经网络对输入序列进行编码,得到隐状态h1,h2,h3...,但是在解码时,每一个输出词都依赖于前一个隐状态以及输入序列每一个对应的隐状态。
更加直观的理解,就是我们在生成一个输出词时,会考虑每一个输入词和当前输出词的对齐关系,对齐越好的词,会有更大的权重,对生成当前输出词的影响就越大。
References
[1] 《百面机器学习》第10章
[2] 梯度消失和梯度爆炸问题详解
http://www.sohu.com/a/332473808_468740
[3] 残差网络ResNet解读(原创)
https://blog.csdn.net/docrazy5351/article/details/78993347
[4] 详解机器学习中的梯度消失、爆炸原因及其解决方法
https://blog.csdn.net/qq_25737169/article/details/78847691