5.1 序列模型
数学符号
假如你想要建立一个能够自动识别句中人名位置的序列模型,那么这就是一个命名实体识别问题,这常用于搜索引擎。在这个例子中,我们约定X<t>来索引输入序列中的位置,例如X<1>表示输入序列中的第一个词。输出也同理,下面的输出y用01来表示其对应的输入是否是人名的一部分。然后用Tx=9表示输入序列的长度。回忆一下之前用X(i)表示第i个样本,所以我们这里用尖括号来区分,现在X(i)<t>表示第i个样本中第t个元素,注意每个样本的元素个数不一样。
想要表示句子里的单词,第一件事就是做一个词表\词典,假如你可以选择一个有一万个常用词的词典,然后句子中的每个单词就用one-hot表示法,也就是说每个单词的表示都是一个一万维的向量,是哪个词就对应位置为1其余都为0。那么这一句中的9个单词就对应9个一万维的向量输出,然后你就可以学习输入和输出的映射,这是一个监督学习问题。那么最后,如果出现一个词典中没有的单词,我们创建一个叫<unknown>的标记来表示这个单词。
注意,这里的one hot向量是输入的表示方法,是已知的,需要学习的映射是这个单词是否是人名。
循环神经网络
我们学习如何训练学习上面讲到的映射的神经网络。假如我们把这9个输入单词(例如可能是9个one hot向量),输入一个标准神经网络,最后输出9个为0或1的项来表示是否是人名。很明显这个结果不好,有两个原因,第一是输入的数据在不同的样本中有不同长度,所以输入和输出的长度是不固定的。第二个是这样的神经网络并不能共享在文本不同位置所学到的特征,我们在文本的识别中希望一个位置的特征是能够影响后面特征的判断的。
这是一个循环神经网络,这张图上讲的比较粗略,我也没太理解。大体上就是第一个输入产生第一个输出,然后将第一个输入的激活值传递给第二个输入,这样以后的每个输入在预测结果的时候都会受到前面所有信息的影响。在这个循环的开始输入一个假的激活值零向量。红色字体是参数,后面会细讲。这个单向循环网络有个问题,例如下面黑色字体这两句话,当我们预测Teddy是否是一个人名的时候,我们只有前两个单词的信息,这完全不足够判断结果,例中的这两句就是不同的结果,说明要做准确的预测我们还需要该位置之后的信息才行,要用到双向循环网络来解决这个问题。
然后看一下具体计算的实现,首先输入的第一个激活值是零向量。后面的计算如公式所示,a<1>这个激活值就是激活函数(上一层的激活值和输入x<1>分别乘上参数加一个偏移量)。这一层的输出y就是一个激活函数里面是a<1>。这里注意参数的下标比较复杂,wax的意思是这个参数是用来算a的,然后这个参数乘以的是x,也就是说它是x的参数。循环神经网络常用激活函数是tanh,有时候也会用ReLU。
然后需要将这个式子简化一下,实际上也就是将上上图最下面的a和y的通用公式,将参数w提出来放进一个向量中,如果两个w都是矩阵,就把两个矩阵横向拼在一起,为了完成之前的乘法功能,还要将后面的a和x纵向拼在一起,这样维数就对了。
通过时间的方向传播(反向传播)
首先图中蓝色字体画出的流程图是前向传播的过程,绿色标出的是计算每个量需要用到的参数。要想完成反向传播,首先需要定义损失函数,我们要注意到每个元素输入的时候都会有一个输出,那么就要有一个损失函数,但是整个序列有许许多多的输入,整体也需要一个损失函数。单个元素y的损失函数和之前二元分类的形式一样(注意当y的结果是0或1的这种二元分类问题,通常都用这个损失函数)。第一行定义的是单个元素的,第二行是整个序列的损失函数,要把每个单独时间步的损失函数都加起来。
对于这个名字“通过时间的方向传播”吴恩达认为,当正向传播时,元素按照时间的顺序逐个输入,反向传播时再按照时间的顺序倒着来,就像时间倒流,所以他认为这个名字很酷。(我不觉得)
不同类型的RNN
上面我们讨论的是输入和输出长度一样的情况,实际上还有很多情况下输入输出是不同长度的,例如语音识别、对一段序列进行分类、视频动作识别、机器翻译(不同语言表达一句话的单词数量不尽相同)。首先之前讲的多个输入对应多个输出的情况,我们将其称为“多对多”结构,输入一个序列输出一个分类我们可以成为“多对一”结构。为了完整性还提了一下一对一,也就是普通网络。
另外还有“一对多”结构,例如你指定一个风格,输出一段音乐。最后,上面提到的多对多是输入和输出一样的结构。这里画了一个多对多,但输出和输出不一样的结构,例如在机器翻译问题中输入和输出长度就是不一样的。那么如图,我们有一个直线型的结构,前半部分叫做编码器,获取输入,后半部分叫做解码器,他会读取整个句子并输出翻译结果。我们可以认为整个句子以某种形式在神经网络上传播。
语言模型和序列生成
假设语音识别系统得到一句话的输入,“the apple and pear salad”,但其中pear有一个音近词pair,那么究竟需要输出哪个单词,就需要语言模型。语言模型将得到的听起来很像的各个句子,计算他们各自的可能性,然后给出概率最高的结果。注意,输入语言模型P的是y而非x,因为是已经识别后的结果,然后再计算每个单词的可能性。
这一节和下一节可能是语音识别特有的,暂时放着
对新序列采样
带有神经网络的梯度消失
如图上蓝色字体写出的句子“The cat, which already ate ……, was full”,这句中是否要使用was/were需要与开头的cat保持一致,但是我们目前见到的基本的RNN模型不擅长捕获这种长期的依赖效应。例如我们之前讲过普通深度网络梯度消失问题,如果有一百多层,那么在反向传播时,y的梯度很难传播到开始的几层,对其产生影响。同样的问题在RNN中也存在,这就意味着很难让神经网络能够意识到它需要记住看到的名词是单数还是复数,并对句子末尾的部分产生影响。
GRU(门控循环单元)
首先定义一个c(memory cell 记忆细胞)作为一个记录(功能相似于编程时的flag),c就等于这一个元素位置的a,也就是说一个一个元素的输入,c就是记录某个位置的输出a,然后在下一个元素输入的时候,判断是否要更新c为新的a。图中c撇就是当前元素的a,然后用Γu计算一个门限值,来决定是否用新的c撇代替原先一直流传下来的c。可以看左上方的流程图,c撇的计算就是a的计算,将输入经过tanh,然后再将参数输入进一个σ函数(其实就是sigmoid),得到Γu,用紫色涂的框就是紫色大括号的公式,也就是决定是否更新c。
结尾介绍了一种更高级的GRU,可用于参考
LSTM
首先,将LSTM单元重复放置在最下面一行,红线画出的是记忆细胞c的一条通路,只有一些线性变换作用在c上,c的值很容易在整个通路上保持不变,这也就实现了长短期记忆。但要注意理解,这里和GRU的区别是c和a不是同一个东西,作为两条线存在,c只用来承载记忆,a才是真正的输入输出用于实现神经网络的预测功能。
详细来看,也就是将上一层的a和本层输入x合起来作为输入分别计算四个值,备选c、更新门u、遗忘门f、输出门o。四个值各有各的参数和函数。遗忘门直接作用于上一层的c,用于选择性遗忘上一层传过来的东西(注意遗忘门使用的是sigmoid,其值在0-1,所以遗忘门应该是长期保持在1附近,表示不忘记,如果需要忘记则偏向0就可以了)。更新门和GRU一样,作为系数乘以备选c,也就是决定这一层多少内容更新到c中。到这里c就可以直接输出了,c只经过了选择性遗忘一次,选择性更新一次两次操作。然后将计算好的c经过一个tanh函数再乘以输出系数输出门o,作为本层a的真正输出。再次把握真正的输出也就是激活值是a而不是c,c只用作承载记忆。
比起GRU,LSTM出现的更早,更加的复杂和强大,三个门使他更加灵活。而GRU相当于一个简化版本,它的优势在于简单,适用于创建更大的网络。
双向RNN
如图所示,前向传播后,再传播回来一次后面的信息形成另外一个a,然后每个输出y 里同时考虑两个a。我们的预测问题应该用不到。
深层RNN
首先排除之前的一个疑问,那就是之前出现的RNN网络,每一个时间节点上真的只有一个神经元,我以为是省略的。
这里出现的深层RNN才首次出现在横向和纵向上都是多层的结构。上图中每个时间点上,都是一个三层的网络(三层在RNN中就已经很深了,因为时间的维度本来就很大),水平的是时间维度。注意箭头的指向,每个隐藏层的a不但接收来自下方本时间点的输入,也接收同一层上一时间点的隐藏层信息,所以这张网络很复杂。同时,也有的网络是在每一层末尾加一些更深的隐藏层,但不水平连接,例如蓝字画出的。