李宏毅机器学习笔记(十)——循环神经网络(RNN)

文章目录

  • 一.时间序列模型与神经网络的改进
  • 二.RNN的各种变种
    • 1.细胞变种——长短期记忆网络(LSTM)
    • 2.结构变种
    • 3.与传统机器学习相融合
  • 三.RNN的梯度下降
  • 四.RNN的应用
    • 1.多输入单输出问题
    • 2.多输入多输出问题
    • 3.阅读理解类问题

一.时间序列模型与神经网络的改进

  本次我们以各种语言处理的问题为例。我们先考虑一个实体识别问题:即输入一句话,输出对应的每个字在这句话中属于哪种定义的实体。
  如果我们套用以前的思路,首先我们要先确定我们的输入。当然输入有很多种处理方式,最简单和常用的就是One-hot词编码,把每个词映射成一个 n n n维向量作为输入,然后使用全连接神经网络作为输出。但有的时候,句子不同,同一个词最后的输出应该不一样,但是普通的神经网络无法做到这一点,相同的输入一定有相同的输出,因此我们就要进行改进,对于每个神经元,不仅要考虑这个输入,还要将以前的一些信息作为输入(当然具体信息是什么这个也有多种选择,例如以前神经元中的内容,或者以前的输入内容再经过一定的处理等等)。从而如下图所示,就是一种把一个简单的二层神经网络的中间层的输出存储了起来,而输入的时候要同样将之前中间层的内容作为输入。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第1张图片  如果我们想看整句话的情况,那就如下图所示。这里可能非常容易陷入一个误区,那就是以为这里面每个所示的是多个神经元;但其实不是,这是**同一个神经元,只是一个个按照时间顺序输入的;也就是黄色的箭头和绿色的箭头是同一个矩阵。**当然,我们可以有多层来处理不同的信息,甚至可以是双向的(先从句子末尾开始学起),这些都是多个神经元,只是画起来就十分复杂晦涩了。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第2张图片
  RNN是一个大类,以上的构造模式经常被称作朴素RNN。

二.RNN的各种变种

1.细胞变种——长短期记忆网络(LSTM)

  有趣的是这个英文名字其实叫Long Short-Term memory,因此含义就是,比较长的短期记忆网络;所以就是在之前的版本上,加上能存储比较长期记忆的神经网络。
  不幸的是LSTM是RNN的一个子类而不是对象,RNN也有很多种实现方式…就比如到底将什么输入,一个神经元内部如何各种杂糅,反正大概能说出道理而且最后的效果不错,那就可以算是一个不错的构造方式,不得不说这也是神经网络一直以来的最大优势和劣势吧
  这里也是介绍比较早期的一种实现方式。
  总得来说就是对于现在的一个输入,首先要经过输入门的控制,来说明如何保留处理输入的内容进入记忆中;之后要再通过遗忘门的控制,来处理目前的记忆;最后再经过输出门的控制,来得到输出结果。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第3张图片
  当然上面只是理论的情况,我们还要处理一些细节的思想。首先就是输入的内容问题,我们其实就可以把我们认为有用的东西都丢进去,然后让机器学习出一个变换矩阵来得到有用的信息即可。而对于门的计算方式,那就比较简单了,就用来做简单的加和乘(对元素进行)来说明权重的改变等等即可,因为具体数值的来源都在前一步的变换中被处理了。
  从而我们可以得到下图中的情况,其中激活函数可自选。其中的所有的 z z z都不同,都是通过矩阵变换来得到的,激活函数是对元素进行。当然,和朴素RNN类似,这个也是只有一个细胞;但是我们可以把每个输入的一个维度的处理看成是一个细胞,从而显得有多个细胞,但是其实意思是一样的。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第4张图片
  我们把上图的形式用简化的符号写下来就得到了如下的结果,类似这种的图网上数不胜数,但都是从这张图开始讲起而没有前面分析结构的内容,从而都比较晦涩难懂。注意到,其实这个LSTM细胞中需要学习的内容其实是画红框的矩阵变换的地方以及激活函数的选取,其他的都是固定的对元素的计算了。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第5张图片
  最后我们把我们的 y y y看成是输出和短期的记忆;把一直不断在更新的记忆内容 c c c看成是比较长期的记忆,从而就实现了长短期记忆的共同记忆;把短期记忆的也作为输入的一部分,将其在时间序列上摊开就得到了如下结果。(当然还要再提醒一遍这都是同一个细胞,训练好之后里面的参数相同,只是每次输入都不相同)
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第6张图片
  当然如果我们不再关注内部的运算法则,我们就可以得到下面的图片。我们也可以看出, h h h和刚才的输出直接相关,因此每次都可能很不相同,是所谓的短期记忆;而 c c c一直从最开始存储在内部,没有经过线性变换,每次进行着更新和遗忘,因此有可能通过学习记住比较长期之前的内容。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第7张图片
  当然LSTM也有不同变种,有更简化一些的GRU,也有更复杂一些的peephole,Clockwise RNN,SCRN等等,但是思想上异曲同工。

2.结构变种

  最流行的结构变种就是上文提到的改成双方向了,这样是两个不同的神经元。最后的结果由这两个神经元的输出共同决定,比如可以使用加权平均的方式等等(当然权重还是交给机器来自己学习)
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第8张图片

3.与传统机器学习相融合

  对于序列模型,有的时候RNN训练的结果还是一些显著特征,还需要通过对这些特征建模才有可能得到更好的结果。因此在LSTM层后面接上HMM/CRF/SVM等传统机器学习结构,在很多问题上有了更好的结果。有关这些算法的内容将在最后讲解,不属于这门课的范围。

三.RNN的梯度下降

  以朴素单层RNN举例。如果输入是 k k k维向量,记忆是 n n n维向量(即输出是一个 n n n维向量),那其实就是用一个 ( k + n ) ∗ k (k+n)*k (k+n)k维的权重矩阵 W W W k k k维的偏移向量 b b b来计算出新的记忆 a a a,再经过softmax回归等得到结果。
  我们大概可以看出,对于一句话的多个输入,会有多个输出。每个输出的损失函数都相当于和上一个的结果直接相连,毕竟 y k + 1 = s o f t m a x ( W ( y k x ) + b ) y^{k+1}=softmax(W(y^kx)+b) yk+1=softmax(W(ykx)+b),而每个y的表达式也含有W的表达式,所以最后的总损失即为每个输出对W的偏导的和。当然实际的表达式形式比较复杂,但是可以看出也可以使用反向传播的原理,即使仅仅只有一个细胞,但是这一个细胞自带一个矩阵的参数,和以前的一层是一样多的参数。
  因此RNN也有对应的梯度下降算法,简称为BPTT,几乎全部是由框架自己进行,不需要自己去计算。
  但是这个朴素RNN存在一个问题,那就是求最后一个的损失值的时候,根据上文分析,有一部分会链导到最开始的情况,而可能每步对W求偏导都会有一个相同的数值(为最简单的单输入单记忆的时候最明显),如果长度过长比如1000,那这个W从1哪怕到1.01,结果就成为了20000+。从而梯度极大;而从0.99变到0,结果都是从不到0.00001变为0,出现了梯度消失。带有更多的解释可参考知乎上的一篇文章:RNN梯度爆炸和消失的原因。反正这就使得训练极其困难,梯度平面就是平原和悬崖各处都是,想得到满意解极其困难。
  当然对于梯度爆炸的情况,我们可以做一个限制:如果梯度大于某个阈值,那么就定义为梯度等于这个阈值,就防止了不会一小心跑出非常远然后崩溃;而对于梯度消失的情况,其实是非常头疼的,但LSTM的出现很好的解决了这一点,觉得以下的文章讲的很好,主要就是因为遗忘门的参数是机器可以自己学习的,而这个参数的改变就可以在链导中改变梯度的大小(当然很多公式是不可避免的,不然无法严格一些的说清楚):为什么LSTM可以解决梯度消失问题。

四.RNN的应用

  这里只是说明一些处理方法,至于最后的效果好不好那还是取决于训练效果。

1.多输入单输出问题

  常见的比如情感分析,关键词抽取等等;输入的是一个句子,输出的只有一个值。
  我们一般采用的就是只抽出最后一个输出,直接做为结果进行训练;或者是将最后一个结果抽出,结合输入的词嵌入文本来放入全连接层中再继续学习(关键词抽取经常这样做)。总之就是关注于最后一个输出。

2.多输入多输出问题

  一般指的是输入输出都长度不确定的情况,使用范围最广。例如机器翻译,语音识别,对话系统等等,都属于这一类问题。
  整体来说,方式如下图所示,首先用一个所谓的作为编码器的LSTM来作为输入,学习到对应的信息;再通过一个所谓的作为解码器的LSTM,根据特征来进行输出。当然,为了防止输出一直循环下去或者是输出重复语言等情况,因此一般来说我们在输出集上还要多两个符号:一个是空符号,代表着被跳过;一个是终结符号,代表着输出结束。
  上述方法不仅理论上貌似可行,实际上确实是可行的,整体结构确实如此,加上一定的辅助操作,得到了不错的结果。
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第9张图片

3.阅读理解类问题

  由于一些更高级比如阅读理解等等可能要通过很长时间的记忆去做出判断和选择的情形,前面LSTM的结构还远远不够用,我们相当于是希望能像人一样,有一个专门的存储记忆的地方,也类似于计算机中的内存一样,什么时候遗忘什么时候拿出来什么时候存入等等做一个控制。
  于是NTM(神经图灵机)应运而生,本质来说就是控制器(比如LSTM)额外去控制一个读指针和写指针,而写指针用于更新内存(但一般是整体更新,而不是更新一个位置,例如使用矩阵乘法或者过滤函数等等),读指针用于从内存中拿出需要的内容,用于共同考虑输出。因此也可以说就是我们把我们的状态转移函数全变成了使用深度学习的方法来进行操作。
  更详细的关于NTM的内容将在论文扩展篇介绍
李宏毅机器学习笔记(十)——循环神经网络(RNN)_第10张图片

你可能感兴趣的:(神经网络,人工智能)