Java教程

深度学习之序列建模初总结

本文主要是介绍深度学习之序列建模初总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

        本文旨在讲解使用深度学习模型对序列数据进行建模,并且主要集中再MLP、RNN、LSTM以及GRU。

MLP

        MLP是最简单的神经网络模型,其就是一个简单的DNN,即全连接前馈深度神经网络。根据通用近似理论,MLP可以近似拟合出任意的连续函数。但是这里有一个基本的前提是,输入数据包含了影响应变量或者说预测变量的所有因子或者说特征,而且数据量需要足够大,这个足够大是相对于噪声和具体模型而言的。实际上,现实情况是,我们并无法在输入数据中包含所有特征,而且现实数据也往往包含较多的噪声,因此,在数据端已经做到相对较好时,我们只能转向对模型的改进,或者说选择可以更好适应数据特点的模型,以更好的提取数据中的信号,做出更好的预测。

        只要数据量足够大,特征足够全,那么通用近似理论告诉我们,MLP其实已经足够了。问题就在于现实情况并非如此。此外,由于MLP模型的输入维度是固定的,即一旦一个MLP模型训练完毕,那么其适用场景就只局限在固定的输入维度上,一旦我们需要扩展输入维度,那么就需要重新训练。比如在NLP或者语音识别中,文本的输入或者语音输入的长度都是可变的,如果对每种长度的输入都需要不同的模型来处理,理论上可以,现实中这完全是一种浪费,无论从哪种角度来说。对此,RNN应运而生。

Simple RNN

        RNN是循环神经网络,是一种专门用来对序列数据进行建模的神经网络。RNN的特点是可以很好的处理变长输入,且可以较好的学习序列数据中的信号。其结构如下所示,其中左图是未展开的形式,包含输入、隐层和输出,右图是左图的展开形式;隐层中的激活函数f一般是双曲正切函数tanh,当然也可以是其他激活函数。从RNN的结构中可以看到,展开的参数U、V和W在每个时间步都是共享的,正是这样的结构使得RNN可以很好的适应变长输入。

        \\h_{t}=f(U\cdot x_{t}+V\cdot h_{t-1}+b_{hidden}) \\ o_{t}=g(W\cdot h_{t}) 

        假设参数在各个时间步不是共享的,那么对应不同长度的输入就有不同的展开长度,从而也就有着不同的参数量,这样在训练的时候依然要根据不同长度的输入分开训练,这和MLP便没啥区别了,因此,从处理变长输入的角度来说,参数共享是必要的。

        此外,我们还可以从序列数据的特点来理解参数共享。序列数据之所以称为序列数据,就是因为序列之间存在着相互依赖的关系,但是要注意的是,参数共享的结构中,其可以学习到的关系应该是属于这类序列的属性,而不是依赖于某些样本,即这种关系应该是非样本特异的,具有不同样本间的普适性。比如,序列的自相关性就是一个例子,只要前一个时间步是较大的值,那么相邻的下一个时间步也大概率具有较大的值(假设正相关),无论这个具体的值是多少。又比如,在NLP任务中,句子的句法结构,也是这种关系的一个例子:动词后面往往跟随的是名词,无论具体的动词或者名词是什么。要注意的是,这种序列层面的规律由于有着不同样本的普适性,因此共享参数就可以很好的习得,但这并不是说非共享的参数就不能习得,其实一个MLP也可以学习位置关系,从而学习到这种规律,只是,既然共享参数已经可以较好的习得,就没必要用更多的参数来学习了,这有助于减少参数量,避免过拟合的问题。

        至此,我们知道,RNN相对于MLP,其具有如下的特点和优势:

1. 由于参数共享,使得其可以很好的训练变长输入;

2. 序列层级的规律只需要共享参数就可以习得,不需要更多的参数;

3. 在序列层级关系的学习中,RNN的参数共享机制显然更加符合奥卡姆剃刀原则,因此,其有效的减少了参数量,降低了过拟合的风险。

        基于上述特点,RNN相比于MLP,更适合对序列数据进行建模,往往会比MLP取得更好的性能。

LSTM

        Simple RNN结构中存在一个大问题:无法训练具有长期依赖的序列。训练神经网络使用的优化方法基本都是梯度下降,在使用梯度下降算法训练Simple RNN时,对于较长的序列,展开之后,会导致在循环的隐层深度过大,从而会导致靠前的输入,即距离最终输出较远的输入,相对于输出的梯度很小,这就使得在训练中,较远的输入对输出的产生不了什么影响,即模型无法学习到具有长期依赖关系的规律,这就是所谓的梯度消失问题。具体对于梯度消失或者梯度爆炸更好的理解,需要先理解BP算法,对此可以参考博主的这篇文章《神经网络反向传播(BP)算法推导》。

        为了解决Simple RNN无法学习具有长期依赖关系的问题,LSTM横空出世。LSTM也属于RNN这大类模型中的一种,其在Simple RNN结构的基础上,对隐层结构进行了改进,使得具有学习长期依赖关系的能力。LSTM模型关键就在于LSTM单元,其结构如下图所示。乍一看,LSTM相比于Simple RNN复杂了许多,容易感觉不知所云,陷入形式化陷阱。实际上,任何学问,背后的道理往往是比较简单朴素的,因此,本文将会一步步拆解LSTM背后的朴素的直观,避免简单的公式堆砌。

 \\f_{t}=\sigma (U_{f}\cdot x_{t}+V_{f}\cdot h_{t-1}+b_{f}) \\i_{t}=\sigma (U_{i}\cdot x_{t}+V_{i}\cdot h_{t-1}+b_{i}) \\o_{t}=\sigma (U_{o}\cdot x_{t}+V_{o}\cdot h_{t-1}+b_{o}) \\\tilde{c}_{t}=tanh(U_c\cdot x_{t}+V_{c}\cdot h_{t-1}+b_{c}) \\c_{t}=i_{t}\cdot \tilde{c}_{t}+f_{t}\cdot c_{t-1} \\h_{t}=o_{t}\cdot tanh(c_{t}) \\o_{t}=tanh(W\cdot h_{t})

        由于LSTM是为了解决Simple RNN无法学习长期依赖关系而提出的,所以我们自然需要从如何解决长期依赖关系这个基本问题出发。Simple RNN无法学习长期依赖关系的根本原因在于一旦序列过长,梯度会指数级的下降,从而使得距离较远的输入对于结果几乎无法产生影响,也就是长期依赖关系无法在这种优化算法下得以体现,从而参数也就无法进行正确的更新,无法学习到长期依赖关系。基于此,我们最朴素的想法就是让输入的影响可以有效的传递到结果处,最简单的就是单位线性传播,即:

\\c_{t}=\tilde c_{t}+c_{t-1}=\sum_{i}^{t}\tilde c_{i} \\h_{t}=tanh(c_{t})

如此,每个时间点的c_t都可以对最终的输出产生显著的影响,不会再因为激活函数小于1的梯度累积而使得对最终输出的影响几乎不存在。这其实就是LSTM引入的CEC(constant error carousel)机制,也叫常量误差传输,还可以称之为记忆单元(memory cell)。

       记忆单元确实可以保存历史的信息,而且可以将其一直无损的传导到最终输出,但是这里还存在着一个明显的问题。因为模型在学习序列关系的时候,输出结果会依赖某些历史神经元,所以历史神经元对输出结果的影响权重应该是不一样的,即某些对输出结果有明显关系或有明显影响的神经元,应该具有更大的权重,而那些无关的神经元则应该赋予更小的权重;但是上述的记忆单元中,对于历史的每个c_t,其权重都是相等的,其系数都为1,这样的话,很可能导致无关的神经元将有明显影响的神经元对输出结果的影响相互抵消,从而使得模型依然很难学到信号。这种现象叫做输入权重冲突,对此,我们很自然想到的解决办法就是把权重也作为学习的对象,这个权重实际上就是上述的输入门i,输入门i受当前输入x和上一步的隐层值h影响,该门经过学习,会对当前新信息加以过滤,如果是对输出有明显影响的输入,则赋予较大权重,即打开门,反之则关闭门;这样就实现了对历史不同输入加以区分。同样的,对于输出,也可能存在输出权重冲突,因此,引入输出门,对最终记忆单元状态中多个节点进行过滤。

        更进一步地,引入输入门是为了对当前新息加以过滤,对于历史信息,也同样需要加以过滤,这是因为序列数据中,有时候输出可能并不怎么依赖历史信息,但是历史记忆单元中的值累计起来是很难发生变化的,难免会对结果造成影响,从而使得这种情况模型很难学习。对此,LSTM又引入了遗忘门f,该门作用在保存历史信息的记忆单元上,这样就会使得模型可以选择性的遗忘历史信息,以避免历史信息对输出结果的干扰。

        至此,通过上述CEC、输入门、输出门和遗忘门的引入,就得到了LSTM完整的形式。这样的LSTM不仅可以克服Simple RNN无法学习长期依赖的问题,还可以对序列数据中的信号进行更加高效正确的学习。CEC机制使得长期依赖得以解决,门的机制使得输出结果对历史信息有了不同权重的连接通路,从而可以更加正确的学习到序列数据中的信号,这正是LSTM如此强大的原因。

        LSTM还存在较多的变体,也在不断的发展,一种更为强大的变体是在LSTM的基础上,对三种门加入了窥视孔连接(peephole),即门不仅仅受上一步隐层值和当前输入的影响,还同时受记忆单元的影响。引入窥视孔连接背后的逻辑在于,门的引入本来就是为了可以动态灵活的对记忆单元中保存的历史信息进行处理,所以门应当收到CEC值的影响,这样可以更加高效的学习。尽管这里门已经受到了隐层值h_t的影响,但是由于h_t同时受到输出门的控制,如果上一步输出门保持关闭,那么h_t-1的值就无法对当前的门起作用,自然的通过h来传导的CEC的状态也同样无法起作用,因此这里直接加入窥视孔连接直接将CEC状态作为门的一个影响因素,就可以避免这个问题。加入了窥视孔连接后,LSTM的形式如下所示。要注意的是,这里的输出门受当前CEC状态影响,而不是上一个CEC。

\\f_{t}=\sigma (U_{f}\cdot x_{t}+V_{f}\cdot h_{t-1}+C_{f}\cdot c_{t-1}+b_{f}) \\i_{t}=\sigma (U_{i}\cdot x_{t}+V_{i}\cdot h_{t-1}+C_{i}\cdot c_{t-1}+b_{i}) \\o_{t}=\sigma (U_{o}\cdot x_{t}+V_{o}\cdot h_{t-1}+C_{o}\cdot c_{t}+b_{o}) \\\tilde{c}_{t}=tanh(U_c\cdot x_{t}+V_{c}\cdot h_{t-1}+b_{c}) \\c_{t}=i_{t}\cdot \tilde{c}_{t}+f_{t}\cdot c_{t-1} \\h_{t}=o_{t}\cdot tanh(c_{t}) \\o_{t}=tanh(W\cdot h_{t})

GRU

        LSTM已经相当强大了,但是相比于Simple RNN,其参数量多了很多,复杂程度的提升也是相当明显的。这就使得无论是在训练还是在推理过程,都会明显变慢许多,尤其是RNN这类模型本身的特点,训练已经是比较慢了。那么是不是可以在LSTM的启发下,简化一下模型,但是不怎么损失性能呢?

        门限模型,也就是GRU,就是在LSTM的启发下,对LSTM进行简化,但是同时相比于LSTM并不怎么会损失性能,有时候还会有更好的性能。所以GRU可以认为是LSTM的一个替代算法。

        GRU相比于LSTM,保留了CEC形式,用重置门r替换了输出门,并且将遗忘门和输入门用一个更新门z和1-z分别表示。LSTM中的输出门是为了避免输出权重冲突,而重置门在上一个隐层值传入之前也进行了过滤,这也会起到LSTM中输出门的作用;此外,使用更新门z来选择性的保留历史信息,同时将过滤掉的1-z比例的历史信息用当前新息进行补充,相当于将LSTM中的遗忘门和输入门的值之和约束成了1。因此,GRU相比于LSTM,少了一个门。

        具体地,GRU的结构和形式如下所示。

\\r_t=\sigma (U_{r}\cdot x_{t}+V_{r}\cdot h_{t-1}+b_{r}) \\z_t=\sigma(U_{z}\cdot x_{t}+V_{z}\cdot h_{t-1}+b_{z}) \\\tilde h_{t}=tanh(U_{h}\cdot x_{t}+V_{h}\cdot(r_{t}\odot h_{t-1})+b_{h}) \\h_{t}=z_{t}\odot h_{t-1}+(1-z_{t})\odot \tilde h_{t-1} \\o_t=g(W\cdot h_{t})

 总结

        从上述对MLP、Simple RNN、LSTM和GRU的讲解中,可以看到深度学习中一种模型研究的典型思路,那就是从优化算法出发,基于基本逻辑,尽量让输出结果和关键结构有着合理的连接,以让模型可以更高效正确的学习到预期的信号。这里合理的连接指的是要使得关键结构可以对输出结果产生有效的影响,从而使得学习可以有效进行。实际上,除了LSTM对Simple RNN的改进,还有注意力模型以及Transformer模型,也是给关键部分提供直接可达的通路,使得学习可以正确高效的进行。此外,对模型性能的优化,我们还可以根据具体任务的不同,修改并设计更合理的目标函数,毕竟目标函数才是学习最根本的驱动和方向。

注:本文所使用的图片均来自维基百科。

这篇关于深度学习之序列建模初总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!