cs224n-Lecture 8 RNN和语言模式

文章目录
  1. 1. 语言模型
  2. 2. n-gram 语言模型
    1. 2.1. n-gram语言模型
    2. 2.2. 稀疏性问题
    3. 2.3. 分母上的数为0
  3. 3. n-gram 模型中的稀疏性问题
  4. 4. n-gram 模型中的存储问题
  5. 5. n-gram 模型实践
  6. 6. 使用n-gram模型生成语言
  7. 7. 一个设定窗口大小的神经语言模型
    1. 7.1. 该模型比n-gram的优势在哪?
    2. 7.2. fixed-window 模型的缺点
  8. 8. 循环神经网络-RNN
  9. 9. RNN语言模型
    1. 9.1. RNN 模型的优点
    2. 9.2. RNN 模型的缺点
  10. 10. 训练一个RNN模型
  11. 11. RNN的反向传播
  12. 12. 使用RNN来进行文本生成
  13. 13. 评估语言模型
  14. 14. 使用RNN进行标记(tagging)
  15. 15. 使用RNN来做句子分类
  16. 16. RNN可以作为编码模块
  17. 17. RNN可以通过声音识别文本

emmmmm这一讲的内容,嗯,好吧,我不太能理解Richard大神上课的方式和讲解(因为本人实在是菜得抠脚),所以这讲的笔记主要是基于cs224n的2019年版的,课程是英文的,还好有字幕,笔记上的内容则根据字幕和个人理解进行翻译,如有错误,还请见谅。

语言模型

语言模型的任务就是预测句子中的下一个词会是什么,如下所示:

语言模型提出一个条件概率分布来计算得到X(t+1)个词是什么,这里假设X(t+1)可以是从一个完整的词汇库V中的任何单词,即我们考虑的是一个预置的单词列表。从这个角度,可以把语言模型看作是一种分类任务,因为存在一些预先设定好的概率。
可以将语言模型看作一个系统,它将概率分配给一段文本。
所以,举个例子,如果我们还有一些文本,x(1)……x(T),那么,文本根据语言模型的概率可以分解。
根据定义,可以说,文本概率就相当于是所有条件概率的乘积。

n-gram 语言模型

n-gram:指一串连续的单词。举个栗子:
1-gram:指一个单词或者是独立的单词,the students opened the,可以是student,也可以是opened或者别的词。
2-gram:指一对连续的单词,比如 the students,students opened,opened their。
其他比如 3-gram 或者 4-gram 都是类似的结构。

n-gram 核心思想:为了预测下一个出现的词是什么,你需要收集一系列的统计,从一些训练数据中找出不同的n-gram组合出现的情况,然后使用这些统计结果来预测下一个单词可能是什么。

假设需要预测第X(t+1)个词是什么,前面只有 n-1 个词:

n-gram语言模型

假设需要学习 4-gram 的语言模型:

一个简单的假设,下一个输出单词仅依赖于前面的三个单词,即前 N-1 个单词。

所以,根据语言模型的计算公式,可以得到:

具体计算如下:

现在的问题是,我们可以放弃监督文本吗(proctor context)?
如果我们扔掉太多的文本,之后我们就无法很好的预测文本的词语。

稀疏性问题

如果分子上的数等于零,会发生什么?
所以,对于一些特定的词W,这个词组 the students opened their W 从来没有在数据中出现过,比如:the students opened their petri dishes,非常不常见,并且在数据中从来没有出现过,这就意味着我们预测下一个词是petri dishes的概率为0。很明显,这样的预测结果出现了问题。


Solution:
对于这个问题的一个局部解法是我们可以增加一个小的delta(Δ)来到所有词汇的计算值当中,因此,所有的词汇预测最终至少都会有一个较小的概率。
因此,petri dishes 也将会有一个较小的概率,但是,也因此其他词语都可能是不好的选项。———平滑化

分母上的数为0

即在训练数据中从来没有见过 student opened their 这个词组。
如果出现这个问题,我们甚至不能计算在这个词组上W的概率分布。


Solution:
如果在语料库中找不到这个词组(student opened their),然后就应该返回,仅考虑需要预测的词的前两个单词而不是前三个词。即,直接考虑 open thier,然后预测下一个词应该是什么。

n-gram 模型中的稀疏性问题

N越大,稀疏性问题就越糟糕。
举个例子,10-gram 或者 9-gram 在语料库中根本就不存在,因此最多只计算 5-gram。

n-gram 模型中的存储问题

需要通过训练语料来计算所有的n-gram,随着N的增加,需要存储的n-grams的数量也会增加,N增加也会导致模型的大小变大。

n-gram 模型实践

你可以通过一个1.7million的语料库构建一个简单的3-gram语言模型

语言模型参考:https://nlpforhackers.io/language-models/

使用n-gram模型生成语言

假设已经知道前两个词是什么,并且后面会出现的词语的概率:

然后选择一些词,并且知道他们的联合概率。
假设给我们的词是 price,所以price就是下一个词,然后你只需要限定前两个词:

重复上面的步骤,将 of 作为预测词,继续通过前两个词预测下一个词:

然后你就能得到一个(乱七八糟的)文本:

其中出现的符号,比如逗号,句号等,也算作是一个字符来进行预测。

一个设定窗口大小的神经语言模型

a fixed-window neural language model
假设我们的窗口大小为4,我们要做的操作类似于NER模型。

使用one-hot向量来表示这些词语,然后,我们将使用这些来查找这些单词的嵌入。所以我们得到了对应的词嵌入矩阵 E1,2,3,4,然后使用e来连接他们。将e通过一个线性层和一个非线性函数 f 来生成某种(some kind of)隐藏层,然后再将它传入另外一个线性层和softmax,现在得到了输出的概率分布y_hat。

在所示的例子中,我们需要预测下一个词是什么,向量y_hat的长度(length,我觉得这里写成大小比较合适)为v其中v是词汇表中所有不同单词的概率。所以神经网络最上层的结构使用的是一个绿色的柱状图来表示,最终的结果可能是 books ,laptops 这些东西。

该模型比n-gram的优势在哪?

1.该模型没有稀疏性问题(sparsity problem);
2.不需要存储所有计算得到的n-grams数据,只需要存储当前词汇表的所有词向量;

fixed-window 模型的缺点

1.fixed window可能会比较小,不管你把窗口调整得多大,当你需要使用的时候,你也可能会失去一些有用的文本;
2.如果你试图去扩大窗口大小(window size),你也需要扩大对应的权重矩阵,即W的宽度,因为W需要和e相乘,e是词嵌入矩阵的连接。W宽度(width of W)增大也就意味着window的增大。
因此,可以得出结论,你的窗口可能永远不会足够大。
示意图如下:

针对 fixed-window神经语言模型,我们需要改进的就是我们需要一个可以处理任何长度输入的神经网络模型。

循环神经网络-RNN

RNN简化结构图如下所示:

我们有一个输入序列 x1,x2,x3…可以把这个序列假设为你喜欢的任何长度。
我们有一个序列的隐藏状态并且有和这些隐藏状态一样多的输入,重要的是,每个隐藏状态的计算是基于先前的隐藏状态和当前的输入步骤。
注意,RNN每个时间步长上的权重W都是相同的,这些特点让我们可以处理任意长度的输入。
每一步的RNN计算都能得到一个输出,也就是对应的y_hat1,y_hat2…它们是可选的因为你不需要计算它们或者你可以只计算一些步骤而不是其他步骤。它依赖于你想让你的RNN做什么。

RNN语言模型

假设有一个给定的句子,构建RNN语言模型,首先使用one-hot向量来表示这些词。然后使用这些来查找词嵌入矩阵中的词嵌入。
计算第一个隐藏状态h1,我们需要基于先前的隐藏状态h0和当前的输入来计算它。我们已经拥有了当前的输入状态E1,问题是,如何来获得h0的状态值?
在先前的状态(previous state)和输入做一个线性转换,再加上一些偏置项(bias),再添加一个非线性层,比如sigmoid,这就给了你一个新的隐藏状态。
通过这样的计算,就能得到一个完整的RNN神经网络。

这是一个语言模型,所以我们需要去预测students opened their后面的词,因此,可以使用当前的状态 h4,将它放入一个线性层,再通过一个softmax函数,然后就可以得到一个基于词汇表的输出分布 y_hat4。
这样也就得到了一些后续可能出现的单词。

RNN 模型的优点

1.RNN可以处理任何长度的输入;
2.计算当前步骤 t 可以使用到先前多次计算的结果;
3.模型大小不会因为更长的输入而改变。
4.每个时间步长上的权重是相同的,处理输入的是对称的。

RNN 模型的缺点

1.由于需要基于先前的状态来计算当前隐藏层的状态,所有的状态无法同时计算,所以计算速度较慢;
2.实际上,从许多步骤返回信息是非常困难的。所以即使我说我们应该能够记住监考老师和时钟并用它来预测考试和我们的课本,RNN证实了至少“我”在上课。

训练一个RNN模型

1.获取一个大的语料库,即一个词组的序列 x(1),x(2),……,x(T);
2.将语料库输入RNN-LM中,计算每步的分布概率 y_hat。
·给出到目前为止所有的单词,预测每个单词的分布概率;
·每一步t的损失函数都是基于预测分布概率y_hat和下一个词真实概率y的交叉熵。
x(t+1)使用one-hot表示。


注:这里的y(t)是one-hot向量,表示真实的下一个词。

·计算每一步t的损失函数的平均值,这会给你一个完整的损失函数设置。


假设语料是:the students open their exams
我们要做的就是在RNN上运行这段文本,在每一个步骤上,我们都会预测一个y_hat值,对于每一个得出的y_hat,你可以计算你的损失值,即J。
在第一步中,损失会是一个负的 log 概率值。
对所有的负概率值求和再计算平均,就是最终的loss值。

然而,计算一整个语料库的损失值和梯度下降,消耗实在是太大了。
在实际中,会把x(1),x(2),……,x(T)看作是一个句子或一个文档。


如果你在训练一个语言模型,你在做的则是计算一个句子的损失,实际上你计算的是一堆句子的梯度,更新权重,不断重复。

RNN的反向传播

RNN的特点是他们在矩阵中使用想用的权重并且不断重复。
问题是:损失函数(loss function)的导数是什么呢?在第t步时,损失对重复权重矩阵 Wh 的导数是什么呢?
损失函数的导数,对应于重复权重的梯度是每一步时间上的梯度之和。

这里有一个问题,在实际情况中如何计算上式中右边的部分中对应权重的梯度?
简单来说,问题就是计算下图中的蓝色部分:

答案是你需要计算反向传播的和,重点是这些不能分开计算,每一个结果都会依赖于先前的结果。

使用RNN来进行文本生成

就像n-gram模型一样,你同样可以使用RNN通过重复的样本来生成文本。
假设我们的第一个词是my,然后进入到模型中,使用输入和初始化的隐藏层,可以得到第一个隐藏状态H1,然后我们可以计算y_hat的分布式概率来得到下一个词是什么,然后我们就能使用分布式来对一些词进行采样。
ok,假设这里采样的词是 favorite,思路就是我们使用输出词作为下一步的输入,将favorite放进RNN的第二步中,然后得到了一个新的隐藏层,一个新的概率分布,从中我们又可以生成一个新的词。

通过重复这些步骤,我们就能不断生成文本。

评估语言模型

语言模型的评估标准是perplexity

这等于交叉熵损失J(θ)的指数:

训练一个语言模型,就是需要将cross-entropy最小化,也就是说你需要将 perplexity 优化得尽可能好。


越小的perplexity越好!

使用RNN进行标记(tagging)

可以使用RNN来进行标记任务:比如词性标注或者命名体识别。

如上图所示,对于每一步输入,RNN都会有一个对应的输出,即对应的tag,所以,通过这种方式就能完成标注。

使用RNN来做句子分类

以下图做情感分析为例:

你可能会对文本使用RNN进行编码,然后你真正想要的是一些句子编码所以你可以输出句子的标签。
如果你有单个向量来表示句子而不是这些离散的向量,这会很有用。


Q:如何对句子做 RNN 编码?
A:使用最终隐藏层状态作为你句子的编码。在RNN中,我们通常使用隐藏层来作为预测输出的东西,所以我们认为最终的隐藏层包含了输出的所有的文本信息,所以,对于这个原因,你或许认为这是一种好的句子编码,我们可以使用它来进行预测。
使用元素最大法(element-wise max)或者元素平均(element-wise mean)通过这些隐藏状态来得到句子编码。

RNN可以作为编码模块

以QA为例,RNN作为编码器的思路是非常常用的。
假如你有一系列的文本,维基百科的文章和贝多芬,然后你有一个问题:
贝多芬的国籍是什么?(what nationality was Beethoven?)
你要做的就是使用RNN来处理这个问题:

RNN的作用就是问题的编码器,你从运行中获得的隐藏状态就表示这个问题。

RNN可以通过声音识别文本

这个部分后续的课程有讲,但是我个人不涉及这个研究领域,因此这里只放出简单的模型结构图。