Course 5-Recurrent Neural Networks--Week 1

吴恩达老师的RNN课程已经学了一遍了,但总觉得自己学得不够明白,怎么办?再来一遍啊。书读百遍其义自见嘛!
第一周的课程主要介绍序列模型的应用场景;深度学习中的RNN基础结构、GRU、LSTM、BRNN;语言模型和序列采样的知识。

1.1 为什么需要序列模型?

本课程中,我们将学习序列模型,深度学习令人兴奋的领域之一。RNN这类模型已经改变了语音识别、自然语言处理等其他领域。在本门课中,你将学习如何自己构建这些模型。我们首先来看一些序列模型派得上用处的例子。

  • 语音识别中,输入是一个裁剪过的语音片段 x ,要求将其映射为文本y,这里的输入和输出都是序列数据,前者是语音序列、后者是文字序列。因此,像RNN及其变种的序列模型在语音识别领域非常有用。
  • 音乐生成是另一个有关序列数据的例子,但在这个例子中,只有输出 y 是序列,输入可以是空集或是一个指定音乐种类的整数或者是音乐的前几个音符。
  • 情感分类中,输入x是一个序列,输出是一个评分。
  • 序列模型在DNA序列分析中也非常有用,DNA是字母A,C,G,T的排列组合。因此,给定一个DNA序列,你可以标记出该DNA序列的哪部分对应一个蛋白质吗?
  • 机器翻译中,给定一个输入序列,要求输出另外一种语言的翻译。
  • 视频行为识别中,给定一个视频帧序列,要求识别行为。
  • 命名实体识别中,给定一个句子,要求确定句子中的人名。

Course 5-Recurrent Neural Networks--Week 1_第1张图片
上述这些问题都可以定位成有监督学习,训练集为(x,y)。但它们又属于不同的序列类型问题。有些序列问题的输入 x 和输出y都是序列,在这种情况下,输入 x 和输出y有可能等长(DNA序列分析,命名实体识别),也有可能不等长(翻译)。在有些序列问题中,只有输入 X 或输出Y是序列。

1.2 符号

上一节中,我们看到了序列模型广泛的应用领域。我们先来定义一些构建序列模型的符号。
假设我们要构建一个序列模型,输入 x 如图所示,取自与《哈利波特》系列。现在要构建一个序列模型来告诉我们句子中人名的位置。这就是命名实体识别(NER)的问题,可用于搜索引擎。比如找出最近24小时内新闻提到的人名,进而对这些人名建立索引。NER可用于查找人名、公司名、时间、地点、国名、货币名等。在这个例子中,我们要构建一个模型,使得对于输入中的每一个单词,都有对应的输出。如果某个单词是人名的一部分,则对应输出位置为1,否则为0。技术上来说,这并不是最好的输出形式,好的表示形式不仅能够告诉我们这是否是人名的一部分,还能告诉我们人名的起始位置。但在这里为了说明问题,采用的是一种比较简单的方式。我们的输入是由9个单词组成的序列,因此,我们会用9个特征来表示这9个单词,并将这些特征索引为序列中的位置。使用x<1>,x<2>,,x<t>,,x<9>来索引输入中的位置,同样的,使用 y<1>,y<2>,,y<t>,,y<9> 来索引输出中的位置。使用 Tx 表示输入 x 的长度,Ty表示输出 y 的长度,本例中Tx=Ty=9。结合之前的标记知识,那么 X(i)<t> 表示第 i 个样本中的第t个元素。因为 Tx 表示输入 x 的长度,那么T(i)x就表示第 i 个输入样本的长度。
Course 5-Recurrent Neural Networks--Week 1_第2张图片
那么在NLP中我们怎样表示这些单词呢,x<1>应该是什么呢?接下来我们讨论一下如何表示这些单词。要想表示句子中的单词,我们首先需要一个词汇表,有时也称之为字典。即是一个单词列表,并且用词汇表中的单词表示句子中的单词。比如词汇表大小为10k,如下图所示。需要注意的是,对于现代NLP来说,10k大小的词汇表是非常小的,对于商业应用来说,较为合理的大小是30k到50k,100k也并不奇怪,有些较大的互联网应用还会用到一百万甚至更大的词汇表。选定词汇表的大小后,怎么样构造出词汇表呢?一种方法就是遍历训练集,找出出现频率最高的前10k个单词;还有一种方法就是寻找一些在线字典,它们胡告诉你,英语里使用最频繁的前10k个单词是什么。接下来,我们就可以用one-hot表示法来表示每一个单词。例子如图中所示。每个one-hot向量的长度是10k,那么我们的目的就是学习一个从x到y的映射。
Course 5-Recurrent Neural Networks--Week 1_第3张图片
还有一个问题是,如果我们遇到一个不在词汇表中的单词该怎么办呢?这时候创造一个单词 <UNK> ,来表示所有不在词汇表中的单词。

1.3 RNN模型

本节讨论如何构建一个模型、构建一个神经网络来学习从x到y的映射。我们可以尝试使用标准神经网络来解决这个问题,比如,将9个one-hot向量输入,经过一些隐藏层,再经过输出层,得到输出,每个输出单元告诉我们每个单词是否是人名的一部分,但是,事实证明,这个方法并不好。如下图所示,主要有两个问题:第一,输入和输出在不同的例子中长度是不同的。即使我们设置句子的最大长度,可以用特定符号进行填充,使句子达到最大的长度,这仍然不是一个好的表达;第二,这个问题就更严重了,这样简单的网络结构并不能共享那些从不同文本位置上学习到的特征。特别的,比如当Harry在位置1时,我们学到了它是人名的一部分,当Harry出现在别的位置的时候,我们希望模型也能判断出它是人名的一部分,有点类似与CNN,希望模型对特征的位置不太敏感。使用更好的表带也会减少模型中参数的数量,之前我们使用得到是one-hot向量,每个向量的长度都是10k,这将是一个非常大的输入层,总的输入大小将是 10k ,第一个隐含层的参数也将非常多。
Course 5-Recurrent Neural Networks--Week 1_第4张图片
下面要介绍的RNN就没有上述两个问题。那么,什么是RNN呢?如果我们从左到右阅读句子,第一个单词是 x<1> ,我们将其输入进神经网络,得到隐藏层输出,进一步可得到输出层输出,告诉我们这个单词是否是人名的一部分。RNN所做的就是,当读到句子中第二个单词 x<2> 时,不仅仅用 x<2>
预测 y<2> ,还会用时刻1时隐藏层计算的输出 a<1> ;下一时刻也是如此,直到最后时刻 Tx 。本例子 Tx=Ty ,RNN结构如下图所示;如果 TxTy ,那么RNN的结构就要做出一些改变。要启动这个RNN,我们还要给出初始的激活值 a<0> >,有些研究人员会随机初始化 a<0> >,但用全0向量初始化,也是一个普遍的选择。
RNN从左往右扫描数据,每一时刻所使用的参数也是共享的,从输入x到隐藏层输出a的参数设为 Wax ,从上一时刻隐藏层输出a到当前时刻隐藏层输出a的参数设为 Waa ,从隐藏层输出a到输出y的参数设为 Wya 。这样,如下图所示,在计算 y<3> 时,不仅使用了 x<3> 的信息,还使用了 x<2> x<1> 的信息。不过目前,这个网络还有一个缺点,就是它在做预测的时候,只使用了当前单词及其之前的单词,并没有使用当前单词之后的单词。比如,给定图中所示两个句子,它们前三个单词都是一样的,但显然Teddy在第一个句子中时人名的一部分,而在第二个句子中并不是。稍后将介绍双向循环神经网络(BRNNs)。不过目前这个单向的RNN就足够我们说明问题了。
Course 5-Recurrent Neural Networks--Week 1_第5张图片
下面用这张整洁的图来说明RNN中的前向计算。前向计算的关键计算式如图中所示,其中,计算隐藏层输出的激活函数通常用tanh,偶尔也用relu,使用tanh后,我们有其他方法来避免梯度消失,避免方法将在本周后面进行讨论。计算输出层输出的激活函数通常取决于问题本身,如果是二分类问题就用sigmoid,如果是多分类问题就用softmax。对于NER问题来说,y只可能是0或者1,那么这里的激活函数就使用sigmoid。图中还给出了更普遍的前向传播公式。
Course 5-Recurrent Neural Networks--Week 1_第6张图片
为了帮助我们构建更复杂的神经网络,我们将上图中的前向传播公式进行简化。如下图所示,将画蓝线的部分进行重写,主要运用分块矩阵的思想。最终可将前向传播公式中参数的脚标简化为只有一个变量。
Course 5-Recurrent Neural Networks--Week 1_第7张图片

1.4 BPTT

我们已经学习了RNN的基础结构,本节将学习RNN中的后向传播是怎么进行的。显然,与之前一样,反向传播的计算步骤与前向传播是相反的。
Course 5-Recurrent Neural Networks--Week 1_第8张图片
前向传播如图所示,为了计算反向传播,我们还需要一个损失函数。我们先来定义一个元素的损失函数,它对应序列中一个具体的单词,使用交叉熵损失函数,如下图所示。然后,对单个单词的损失函数按照时间求和,就可得到整个序列的损失。反向传播如红线所示,通过对损失函数求导,梯度下降法更新,不断优化参数。
Course 5-Recurrent Neural Networks--Week 1_第9张图片
目前为止,我们只学到了一种RNN的结构,即输出和输出等长的RNN。下面我们要学习其他类型的RNNs。

1.5 不同类型的RNN网络

目前为止,我们已经了解了输出序列和输出序列等长时的RNN。但对于其他应用来说, Tx Ty 不会总相等,在本小节中,你将看到更丰富的RNN家族。
大家是否还记得下图所示的ppt,这是我们在本周第一课中的ppt。这里面展示了输入和输出的各种情况。比如,音乐生成的例子,输入就是空集或者一个整数;再比如电影情感分类,输出就是一个1-5的整数,而输入确实一个序列;在NER中,输入和输出向等长的;但也有一些应用中,输入和输出是不等长的,比如机器翻译。因此,我们可以通过修改基本的RNN模型来处理这些问题。
Course 5-Recurrent Neural Networks--Week 1_第10张图片
如下图所示。

  • NER这种应用,我们称之为多对多结构。
  • 情感分类应用,我们称之为多对一结构。
  • 当然了,还有一对一结构,这种我们并不感兴趣。

Course 5-Recurrent Neural Networks--Week 1_第11张图片

  • 音乐生成应用,我们称之为一对多结构。
  • 机器翻译应用,我们称之为多对多结构,它是一种特殊的多对多,因为输入和输出的长度是不相同的。这种结构由两部分组成,分别是编码器和解码器。
    再这周结束的时候,你将会对这些结构组件有一个更好的理解。从技术上来说,还有一种结构,那就是基于注意的结构。

Course 5-Recurrent Neural Networks--Week 1_第12张图片
现在来总结一下RNN的结构类型。如下图所示。如果将一对一的 a<0> 不要,那这就是我们的标准神经网络。
Course 5-Recurrent Neural Networks--Week 1_第13张图片
下面将介绍序列生成的相关内容。

1.6 语言模型和序列生成

语言建模是NLP中最基础也是最重要的任务之一。而RNN再这一方面就做得很好。本节我们将学习到如何用RNN来构建一个语言模型。
那么,什么是语言模型呢?假设我们在构建一个语音识别系统,听到了一句”The apple and pear salad was delicious.” 那么,所说的可能是下面两种可能的句子,如图所示。人会认为说的是第二个句子,而这就是一个好的语音识别系统所要做的事情,尽管这两个句子听起来几乎一样。而让语音识别系统选择第二个句子的方法就是使用语言模型。语言模型能输出这两句话出现的概率。比如,某一语言模型计算出两句话的概率分别如下图所示。因此,语言模型所做的工作就是,给定任何一句话,告诉我们这句话出现的概率。这一点是语音识别系统和机器翻译的基础。因此,语言模型的基本工作就是对输入的句子序列 y<1>,y<2>,...,y<Ty> ,计算其出现的概率。
Course 5-Recurrent Neural Networks--Week 1_第14张图片
那么,如何建立一个语言模型呢?用RNN建立一个这样的模型,首先需要一个训练集,它包含大量英文文本语料,或者是任何一种想要在其之上建立语言模型的语种文本。单词corpus是NLP中的专有名词,表示大量文本或句子的集合。
假设语料中有一句话”Cats average 15 hours of sleep a day.” 那么,我们首先要做的就是,符号化句子(tokenize this sentence),意思就是利用训练集形成一个词汇表,然后将每个单词映射为词汇表中的索引,再将索引值转化为one-hot向量,记为 y<1>,y<2>,...,y<Ty> 。我们还要做的一件事是标记句子的结尾。因此,我们还要添加一个额外的标记 <EOS> ,表示end of sentence。如果我们想模型明确捕捉到句子什么时候结束,就要将EOS标记放在每个句子的结尾处。算上EOS,图中这句话总共有9个输入。在我们自己做符号化过程的时候,我们可以自行决定要不要把标点符号考虑在内。显然,下图所示的例子忽略了标点符号。如果训练集中的有些单词不在词汇表中,我们应该怎么办呢?这时候,我们就把这些单词替换成一个唯一的符号 <UNK> ,表示unknow word,然后我们只对 <UNK> 进行概率建模,而不再对那些一个个的单词概率建模。
完成符号化步骤之后(即,将输入句子映射为在词汇表中的一个个独立的符号)。
Course 5-Recurrent Neural Networks--Week 1_第15张图片
接下来,我们构建一个RNN来对这些不同序列的概率进行建模。在这个RNN中,我们设 x<t>=y<t1> 。初始状态下,设 a<0> x<1> 均为0向量,通过softmax得到 y<1> 最有可能的输出,也就是得到词汇表中每个单词的概率,从第一个单词a一直到最后一个单词zulu,再到unk和eos。这样,softmax的结果就有10002个结果。然后,RNN进入下一时刻,此时的输入仍然是前一时刻的激活值 a<1> 和当前时刻的输入值 a<2> ,只不过,这时的 x<2>=y<1> ,输出 y<2> 同样经过softmax计算得到,只不过这时相当于在计算一个条件概率 p(y<2>|y<1>) 。之后时刻的输出也是在计算条件概率,只不过条件是当前预测词前面所有的单词。
然后,为了训练模型,我们需要定义代价函数,由于输出层是softmax激活函数,我们这里使用softmax的损失函数,那么,整个序列的代价就是把各个时刻的损失都相加起来。
而最终,这个序列出现的概率就是把所有的输出相乘,就得到了这个序列的联合概率密度。
Course 5-Recurrent Neural Networks--Week 1_第16张图片
上述就是训练RNN语言模型的基本结构,也许一些细节对你来说还比较抽象,别担心,这周的编程练习会让你更加清楚。
下面,我们将用语言模型进行一个非常有趣的事情,那就是从语言模型中采样一个序列。

1.7 采样新的序列

在你训练完成一个序列模型之后,一种让你能大概了解到模型学了些什么的方法就是进行一次序列采样。我们来看看应该怎么做。
首先要记得,序列模型对任意特定单词序列的概率进行建模,即对序列的联合概率进行建模。而我们要做的就是从这个概率分布中进行采样,进而生成新的单词序列。
模型的训练使用下图中上面所示的结构。而对于采样就稍有不同了,我们要对模型生成的第一个单词进行采样。初始输入仍然是 a<0> x<1> 均为0向量, y<1> 仍然是一个经过softmax输出得到的概率分布,而我们要做的就是在这个softmax输出上随机采样,并把随机采样的结果作为第二时刻的输入。这里需要注意的是,在模型训练过程中, x<t>=y<t1> ;而在采样序列时, x<t>=y^<t1> 而第二时刻的输出也是随机选择的,后面几个时刻也是进行相同的操作。
那么,怎样知道序列结束了呢?如果eos是词汇表中的一部分,那么我们可以不断采样,直到采样到eos;如果eos不在词汇表中,我们可以设定采样的长度,直到序列达到规定长度为止。不过在这一过程中,也有可能产生unk这个符号,如果你想确定算法不会产生这个符号,一种可行的方法就是拒绝任何unk的输出,当输出是unk的时候就继续采样。
上述就是如何从RNN语言模型中生成随机序列的例子。
Course 5-Recurrent Neural Networks--Week 1_第17张图片
目前为止,我们构建了一个单词层面的RNN模型,即词汇表中都是一些英语单词。取决于我们的应用场景,我们还可以构建一个字符层面的RNN模型。在这种情况下,词汇表就包含了a-z的26个字母、空格符、标点符号、0-9的10个数字,如果想区分大小写,还可以加上大写的26个字母。我们可以通过观察词汇表出现的字符得到字符层面的词汇表。在字符层面上, y<1>,y<2>,...,y<Ty> 就不再是单词序列了,而是句子序列中的一个个字符。这种表示优缺点并存。优点是不再担心unknow 单词的出现;而主要的缺点就是序列的长度变得很长很长。一般的英文句子都是10-20个单词,包含的字符就很很多,使得单词之间的依赖关系减弱,计算成本增加。目前在NLP领域还是使用单词层面的语言模型居多,但随着硬件的发展,在一些特定领域,如在大量专用或未知单词的情况下,人们还是会用字符层面的语言模型。
Course 5-Recurrent Neural Networks--Week 1_第18张图片
下面是一些有趣的例子,它们都是从语言模型中采样出来的。
Course 5-Recurrent Neural Networks--Week 1_第19张图片
以上就是基础的RNN结构,以及如何进行训练和采样。接下来将讨论训练RNN的挑战,以及如何适应这些挑战,特别是梯度消失问题,通过建立更强大的RNN模型来解决。

1.8 RNN的梯度消失问题

我们已经了解了RNN是如何工作的、如何运用RNN解决命名实体识别以及语言建模等问题。但是基础的RNN算法有一个问题,那就是梯度消失问题。我们先来讨论这个问题,然后再说明怎么解决这个问题。
我们看到的RNN都长下图的样子。现在,我们以语言模型为例进行说明。句子如下图蓝色笔迹所示,其中,cat和was对应,cats和were对应。这是一个句子中有长程依赖的例子。但是基础的RNN结构并不善于捕捉这种长程依赖。为什么呢?你可能还记得我们在讨论非常深的神经网络时,说到的梯度消失问题。当网络很深的时候,就很难将输出的梯度反向传播到最初的几层上。RNN也是同样的道理。当序列很长的时候,后面时刻的梯度就很难传播到最初时刻上加以计算。实际上,就是网络只能记住它前面几个时刻的信息,隔得太远就记不住了。除了梯度消失,还有个梯度爆炸的问题。但是梯度爆炸要好发现和解决的多,当你看到计算结果有很多NaN出现,这就说明出现梯度爆炸了,其中一个解决方法就是使用gradient clipping。其思想就是给梯度值设置一个范围,如果在这个范围内就用梯度原来的值;如果小于范围内的最小值,就将梯度设置为范围内的最小值;如果大于范围内的最大值,就将梯度设置为范围内的最大值。
Course 5-Recurrent Neural Networks--Week 1_第20张图片
相较而言,梯度消失问题就比较难解决了。下面我们将重点讨论梯度消失的问题及其解决方法。

1.9 GRU

我们已经了解了基本的RNN是怎样工作的。本节我们将学习GRU,它是RNN中隐藏层的一种改进,使得RNN可以更好的捕捉长程依赖,从而有助于梯度消失问题的解决。
下图中激活值的计算想必大家都很熟悉了,将这个表达式转化成计算图的形式,就如图中左边部分所示。
Course 5-Recurrent Neural Networks--Week 1_第21张图片
在GRU单元中,为了使RNN能具有长程依赖,我们增加一个变量 c ,并称之为记忆单元,为循环单元提供了记忆能力。并令c<t>=a<t>,以下是GRU单元的计算过程

c~<t>=tanh(Wc[c<t1>,x<t>]+bc)

c<t> 决定了每个时刻的记忆。
Γu=σ(Wu[c<t1>,x<t>]+bu)

sigmoid函数的取值基本上不是接近0就是接近1, Γu 决定了什么时候更新。
c<t>=Γuc~<t>+(1Γu)c<t1>

*表示对应元素的乘积。需要注意的是,如果 Γu=1 ,那么 c<t>=c~<t> ;如果 Γu=0 ,那么 c<t>=c<t1> 。这样就避免了梯度消失问题。
上述一系列式子中, c<t> 表示向量, c~<t> Γu c<t> 具有相同的shape。
Course 5-Recurrent Neural Networks--Week 1_第22张图片
上述都是简化过的GRU,下面来讨论完整的GRU应该是什么样子。(注意,最后一个式子有误,应该是 (1Γu)c<t1> 。第一个式子中加上 Γr ,其中 r 代表相关性。Γr 表示 c<t1> c~<t> 之间的相关性。如下图所示, Γr Γu 的计算方法是一样的,只不过参数不同。
Course 5-Recurrent Neural Networks--Week 1_第23张图片

1.10 LSTM

另一个比GRU还强大和通用的网络单元就是LSTM。下图给出了它们两个的计算对比。LSTM有3个门函数,分别是更新门、遗忘门和输出门。
Course 5-Recurrent Neural Networks--Week 1_第24张图片
将LSTM的计算式转化成计算图如下图右上角所示。而真正的使用了LSTM的RNN结构如下图下面的结构所示。其中红线表示的一条路径就是网络中的记忆信息的传输过程,我们可以通过设置恰当的参数,使得 c<0> 一直传输下去。
在此基础上也有些变体的版本,如绿色笔迹所示,在计算 ΓuΓfΓo 时,不仅使用 a<t1>,x<t> ,还使用 c<t1> ,这种网络叫做peephole connection。
Course 5-Recurrent Neural Networks--Week 1_第25张图片
什么时候使用GRU,什么时候使用LSTM并没有一个统一的标准。GRU 更简单,因此更容易创建一个更大的网络,运算也会更快。而LSTM更强大和灵活,因为它有3个门。如果一定要选择一个的话,大多数人还是会选择LSTM

1.11 BiRNN

目前为止,你已经了解到了RNN中大多数重要的组件。但还有两个思想可以帮助你构建更强大的模型。其中一个思想就是双向RNN,它可以帮助我们在某个时刻同时使用之前和之后的信息。另一个就是深度RNN,我们将在下节介绍。
我们先来看看双向RNN。例子仍然是我们之前讨论的那个NER的问题。下图中所示的矩形框既可以表示标准的RNN块,也可以表示GRU或者LSTM。只要这些模块都是前向的。
Course 5-Recurrent Neural Networks--Week 1_第26张图片
那么,BRNN又是什么样子的呢?它的隐藏层有一个前向的循环单元,依次计算各个隐藏单元的输出;同时,它还有一个后向的循环单元。前、后向的隐藏单元都计算完成后,就可以计算预测结果了。同样的,下图中的矩形块可以是基础RNN、GRU或LSTM中的一种。事实上,除了实时的语音识别系统用的是更复杂的网络结构外,对于很多NLP问题,有LSTM单元的BRNN是用的很普遍的。因此,当我们在进行NLP问题时,并且句子都是完整的,就可以使用BRNN,而这也成为RNN的缺点。
Course 5-Recurrent Neural Networks--Week 1_第27张图片

1.12 深度RNNs

目前我们所看到的不同版本的RNN都能工作的很好。但在学习非常复杂的函数的时候,把多个RNN堆叠起来构建更深的网络会更有用。本小结将学习如何构建更深的RNN。
下图左边画出了一个标准神经网络,深度RNN和这个有点像,如下图所示。并以 a[2]<3> 为例,介绍了网络中的激活单元如何计算。需要中注意的是,同一层的参数都是共享的。对于左边的标准神经网络,我们可能见过深度达100层以上的网络,但是对于RNN来说,三层就已经很多了。因为要加上时间维度,这样网络就变得非常大了。
Course 5-Recurrent Neural Networks--Week 1_第28张图片
有时还会看到的一种网络结构就是下图中所示的这样,在输出层之前再加几层隐藏层,但是隐藏层之间没有水平连接。这种结构我们会见的多一点。同样的,这些矩阵块可以是基础的RNN、GRU或者LSTM,我们也可以把这个网络构建成双向的。
Course 5-Recurrent Neural Networks--Week 1_第29张图片

你可能感兴趣的:(深度学习,深度学习)