第一周 循环序列模型(Recurrent Neural Networks)
1.1 为什么选择序列模型?(Why Sequence Models?)
语音识别:给定一个输入音频片段 X,要求输出对应的文字记录 Y。输入和输出数据都是序列模型,因为 X是一个按时播放的音频片段,输出 Y是一系列单词
音乐生成问题:只有输出数据 Y是序列,而输入数据可以是空集,也可以是个单一的整数,这个数可能指代想要生成的音乐风格,或者想要生成的那首曲子的头几个音符
处理情感分类:输入数据 X是序列,会得到类似这样的输入:“There is nothing to like in this movie.”,你认为这句评论对应几星?
DNA序列分析:DNA用A、C、G、T四个字母来表示。给定一段DNA序列,能够标记出哪部分是匹配某种蛋白质?
机器翻译:输入句:“Voulez-vou chante avecmoi?”(法语:要和我一起唱么?),要求输出另一种语言的翻译结果
视频行为识别:得到一系列视频帧,要求识别其中的行为
命名实体识别:给定一个句子,要求识别出句中的人名

这些问题都可以被称作使用标签数据 (X,Y)作为训练集的监督学习。但序列问题有很多不同类型。有些问题里,输入数据 X和输出数据Y都是序列,但就算在那种情况下,X和Y有时也会不一样长。或者像上图编号1和编号2所示的X和Y有相同的数据长度。在另一些问题里,只有 X或者只有Y是序列
1.2 数学符号(Notation)
序列模型的输入语句是:“Harry Potter and Herminoe Granger invented a new spell.”。假如想要建立一个能够自动识别句中人名位置的序列模型,那么这就是一个命名实体识别问题

该句话包含9个单词,输出y即为1 x 9向量,每位表征对应单词是否为人名的一部分,对应的输出y表示为:
y<t>表示序列对应位置的输出,Ty表示输出序列长度,1≤t≤Ty
对于输入x,表示为:
x<t>表示序列对应位置的输入,Tx表示输入序列长度。此例中Tx=Ty,但是也存在Tx=Ty
如何表示每个x<t>:
建立一个词汇库vocabulary,尽可能包含更多的词汇。例如一个包含10000个词汇的词汇库为:
然后使用one-hot编码,词汇表中与x<t>对应的位置为1,其它位置为0。如果出现词汇表之外的单词,可以使用UNK或其他字符串来表示

对于多样本:对应的命名规则可表示为:X(i)<t>,Y(i)<t>,Tx(i),Ty(i),i表示第i个样本。不同样本的Tx(i)或Ty(i)都有可能不同
1.3 循环神经网络模型(Recurrent Neural Network Model)
序列模型从左到右,依次传递,此例中,Tx=Ty。x<t>到y^<t>之间是隐藏神经元。a<t>会传入到第t+1元素中,作为输入。其中,a<0>一般为零向量

循环神经网络是从左向右扫描数据,同时每个时间步的参数也是共享的,用Wax来表示管理着从x<1>到隐藏层的连接的一系列参数,每个时间步使用的都是相同的参数Wax。而激活值是由参数Waa决定,同时每一个时间步都使用相同的参数Waa,同样的输出结果由Wya决定:

预测y^<3>时,不仅要使用x<3>的信息,还要使用来自x<1>和x<2>的信息,而这个循环神经网络的一个缺点是只使用了这个序列中之前的信息来做出预测,因为如果给定了这个句子,“Teddy Roosevelt was a great President.”,为了判断Teddy是否是人名的一部分,仅仅知道句中前两个词是完全不够的,还需要知道句中后部分的信息,因为句子也可能是这样的,“Teddy bears are on sale!”。因此如果只给定前三个单词,是不可能确切地知道Teddy是否是人名的一部分,第一个例子是人名,第二个例子就不是,所以不可能只看前三个单词就能分辨出其中的区别
所以这样特定的神经网络结构的一个限制是它在某一时刻的预测仅使用了从序列之前的输入信息,并没有使用序列中后部分的信息
RNN的正向传播(Forward Propagation)过程为:

为了简化表达式,可以对a<t>项进行整合:
则正向传播可表示为:

RNN前向传播示意图:

1.4 通过时间的反向传播(Backpropagation through time)
反向传播计算方向与前向传播基本上是相反:

识别人名的例子,经过RNN正向传播,单个元素的Loss function为:
这是 binary classification 的 Loss Function,注意与1.6 的softmax Loss Function区别
该样本所有元素的Loss function为:
反向传播(Backpropagation)过程就是从右到左分别计算L(y^,y)对参数Wa,Wy,ba,by的偏导数,这种从右到左的求导过程被称为Backpropagation through time
RNN反向传播示意图:

1.5 不同类型的循环神经网络(Different types of RNNs)
RNN模型包含以下几个类型:
一对一,当去掉a<0>时它就是一种标准类型的神经网络
一对多,比如音乐生成或者序列生成
多对一,如是情感分类的例子,首先读取输入,一个电影评论的文本,然后判断他们是否喜欢电影还是不喜欢
多对多,如命名实体识别,Tx=Ty
多对多,如机器翻译,Tx=Ty

1.6 语言模型和序列生成(Language model and sequence generation)
在语音识别中,某句语音有两种翻译:
the apple and pair salad
the apple and pear salad
语言模型会计算出这两句话各自的出现概率:
P(The apple and pair salad)=3.2×10−13
P(The apple and pear salad)=5.7×10−10
选择概率最大的语句作为正确的翻译
概率计算的表达式为:
如何使用RNN构建语言模型:
首先需要一个足够大的训练集,训练集由大量的单词语句语料库(corpus)构成。然后,对corpus的每句话进行切分词(tokenize),建立vocabulary,对每个单词进行one-hot编码。例如下面这句话:
The Egyptian Mau is a bread of cat.
每句话结束末尾,需要加上< EOS >作为语句结束符。若语句中有词汇表中没有的单词,用< UNK >表示。假设单词“Mau”不在词汇表中,则上面这句话可表示为:
The Egyptian < UNK > is a bread of cat. < EOS >
准备好训练集并对语料库进行切分词等处理之后,接下来构建相应的RNN模型:
x<1>和a<0>均为零向量。Softmax输出层y^<1>表示出现该语句第一个单词的概率,softmax输出层y^<2>表示在第一个单词基础上出现第二个单词的概率,即条件概率,以此类推,最后是出现< EOS >的条件概率
单个元素的softmax loss function为:
这是softmax Loss Function ,注意与1.4 binary classification 的 Loss Function区别
该样本所有元素的Loss function为:
对语料库的每条语句进行RNN模型训练,最终得到的模型可以根据给出语句的前几个单词预测其余部分,将语句补充完整。例如给出“Cats average 15”,RNN模型可能预测完整的语句是“Cats average 15 hours of sleep a day.”
整个语句出现的概率等于语句中所有元素出现的条件概率乘积。例如某个语句包含y<1>,y<2>,y<3>,则整个语句出现的概率为:
1.7 对新序列采样(Sampling novel sequences)
基于词汇的RNN模型
序列模型模拟了任意特定单词序列的概率,要做的是对这些概率分布进行采样来生成一个新的单词序列。编号1所示的网络已经被上方所展示的结构训练过,编号2是进行采样

第一步要做的是对想要模型生成的第一个词进行采样,输入x<1>=0,a<0>=0,第一个时间步得到的是所有可能的输出,是经过softmax层后得到的概率,然后根据这个softmax的分布进行随机采样。对这个向量使用np.random.choice,来根据向量中这些概率的分布进行采样,就能对第一个词进行采样
然后继续下一个时间步,y^<1>作为输入(编号4),然后softmax层就会预测y^<2>是什么。假如第一个词进行抽样后得到的是The,现在要计算出在第一词是The的情况下,第二个词应该是什么(编号5),然后再用采样函数来对y^<2>进行采样
即无论得到什么样的用one-hot码表示的选择结果,都把它传递到下一个时间步,然后进行采样,直到最后一个时间步
怎样知道一个句子结束:
如果代表句子结尾的标识在字典中,可以一直进行采样直到得到EOS标识(编号6),代表着已经抵达结尾,可以停止采样
如果字典中没有这个词,可以决定从20个或100个或其他个单词进行采样,然后一直将采样进行下去直到达到所设定的时间步。不过这种过程有时候会产生一些未知标识(编号7),如果要确保算法不会输出这种标识,要做的是拒绝采样过程中产生任何未知的标识,一旦出现就继续在剩下的词中进行重采样,直到得到一个不是未知标识的词
这就是如何从RNN语言模型中生成一个随机选择的句子。以上所建立的是基于词汇的RNN模型,意思就是字典中的词都是英语单词(下图编号1)

基于字符的RNN结构
用以上字符组成字典(上图编号2所示)
序列y^<1>,y^<2>,y^<3>在训练数据中是单独的字符,对于“Cats average 15 hours of sleep a day.”,C是y^<1>,a就是y^<2>,t就是y^<3>等等
优点:
不必担心会出现未知的标识,基于字符的语言模型会将Mau这样的序列也视为可能性非零的序列。而基于词汇的语言模型,如果Mau不在字典中,只能当作未知标识UNK
缺点:
最后会得到太多太长的序列,基于字符的语言模型在捕捉句子中的依赖关系也就是句子较前部分如何影响较后部分不如基于词汇的语言模型那样可以捕捉长范围的关系,并且基于字符的语言模型训练起来计算成本比较高
1.8 循环神经网络的梯度消失(Vanishing gradients withRNNs)

编号1cat是单数,应该用was,编号2 cats是复数,用were
这个例子中的句子有长期的依赖,最前面的单词对句子后面的单词有影响。但基本的RNN模型(编号3)不擅长捕获长期依赖效应
RNN反向传播很困难,会有梯度消失的问题,后面层的输出误差(编号6)很难影响前面层(编号7)的计算。即很难让一个神经网络能够意识到它要记住看到的是单数名词还是复数名词,然后在序列后面生成依赖单复数形式的was或者were。且在英语里面中间的内容(编号8)可以任意长,所以基本的RNN模型会有很多局部影响,输出y^<3>主要受附近的值(编号10)的影响,编号6所示的输出很难受到序列靠前的输入(编号10)的影响,因为不管输出是什么,对的还是错的,这个区域都很难反向传播到序列的前面部分,也因此网络很难调整序列前面的计算
在反向传播的时候,随着层数的增多,梯度不仅可能指数型的下降,也可能指数型的上升。梯度消失在训练RNN时是首要的问题,不过梯度爆炸也会出现,但是梯度爆炸很明显,因为指数级大的梯度会让参数变得极其大,以至于网络参数崩溃。参数大到崩溃会看到很多NaN,或者不是数字的情况,这意味着网络计算出现了数值溢出
解决方法:用梯度修剪。梯度向量如果大于某个阈值,缩放梯度向量,保证不会太大
1.9 GRU单元(Gated Recurrent Unit(GRU))
门控循环单元:改变了RNN的隐藏层,使其可以更好地捕捉深层连接,并改善了梯度消失问题
简化的GRU模型
RNN隐藏层的单元的可视化:

a<t>表达式为:
为了解决梯度消失问题,对上述单元进行修改,添加了记忆单元,构建GRU,如下图所示:

表达式为:
c<t−1>=a<t−1>,c<t>=a<t>。符号c表示记忆细胞的值,a表示输出的激活值,c~<t>是个候选值,替代了c的值,Γu(0到1)意为gate,u表示“update”,当Γu=1时,代表更新;当Γu=0时,代表记忆,保留之前的模块输出。Γu能够保证RNN模型中跨度很大的依赖关系不受影响,消除梯度消失问题
完整的GRU
完整的GRU添加了另外一个gate,即Γr,表达式如下:
Γr门:计算出的下一个c<t>的候选值c~<t>跟c<t−1>有多大的相关性
c<t>可以是一个向量(编号1),如果有100维的隐藏的激活值,那么c<t>、c~<t>、Γu还有画在框中的其他值也是100维

∗实际上就是元素对应的乘积(c<t>=Γu∗c~<t>+(1−Γu)∗c<t−1>),若Γu(Γu=σ(Wu[c<t−1>,x<t>]+bu))是一个100维的向量,而里面的值几乎都是0或者1,则这100维的记忆细胞c<t>(c<t>=a<t>,编号1)就是要更新的比特
1.10 长短期记忆(LSTM(long short term memory)unit)
LSTM是另一种更强大的解决梯度消失问题的方法。它对应的RNN隐藏层单元结构如下图所示:

相应的表达式为:
LSTM包含三个gates:Γu,Γf,Γo,分别对应update gate,forget gate和output gate
在LSTM中不再有a<t>=c<t>的情况
红线显示了只要正确地设置了遗忘门和更新门,LSTM很容易把c<0>的值一直往下传递到右边,比如c<3>=c<0>。这就是为什么LSTM和GRU非常擅长于长时间记忆某个值

“窥视孔连接”(peephole connection):门值不仅取决于a<t−1>和x<t>,也取决于上一个记忆细胞的值(c<t−1>),即c<t−1>也能影响门值
如果考虑c<t−1>对Γu,Γf,Γo的影响,可加入“窥视孔连接”,对LSTM的表达式进行修改:
LSTM主要的区别:比如(上图编号13)有一个100维的隐藏记忆细胞单元,第i个c<t−1>的元素只会影响第i个元素对应的那个门,所以关系是一对一的,并不是任意这100维的c<t−1>可以影响所有的门元素
LSTM前向传播图:

GRU:模型简单,更容易创建一个更大的网络,只有两个门,在计算上运行得更快,且可以扩大模型的规模
LSTM:更加强大和灵活,因为它有三个门而不是两个
1.11 双向循环神经网络(Bidirectional RNN)
双向RNN模型在序列的某点处不仅可以获取之前的信息,还可以获取未来的信息
用只有4个单词的句子,x<1>到x<4>。这个网络有一个前向的循环单元a→<1>,a→<2>,a→<3>,a→<4>,这四个循环单元都有一个当前输入x输入进去,得到预测的y^<1>,y^<2>,y^<3>和y^<4>
再增加一个反向循环层:a←<1>,a←<2>,a←<3>,a←<4>

给定一个输入序列x<1>到x<4>,这个序列先后计算前向的a→<1>,a→<2>,a→<3>,a→<4>,而反向序列从a←<4>开始,计算完了反向的a←<4>,可以用这些激活值计算反向a←<3>,a←<2>,a←<1>
值得注意的是计算的是网络激活值,这不是反向传播而是前向的传播,图中前向传播一部分计算是从左到右,一部分计算是从右到左。把所有激活值都计算完了就可以计算预测结果

预测结果:
这些基本单元不仅仅是标准RNN单元,也可以是GRU单元或者LSTM单元
双向RNN网络模型的缺点是需要完整的数据的序列才能预测任意位置。比如要构建一个语音识别系统,双向RNN模型需要等待整个语音说完,获取整个语音表达才能处理这段语音,并进一步做语音识别
1.12 深层循环神经网络(Deep RNNs)

a[l]表示第l层的激活值,<t>表示第t个时间点
激活值a[l]<t>有两个输入:
对于RNN来说,有三层就已经不少了。由于时间的维度,RNN网络会变得相当大,即使只有很少的几层
另外一种Deep RNNs结构是每个输出层上还有一些垂直单元:
即把输出去掉(编号1),在每一个上面堆叠循环层,然后换成一些深的层,这些层并不水平连接,只是一个深层的网络,然后用来预测y<t>
这些单元(编号3)没必要是标准的RNN,也可以是GRU单元或者LSTM单元,也可以构建深层的双向RNN网络,但深层的RNN训练需要很多计算资源,需要很长的时间
Last updated