Loading [MathJax]/jax/output/HTML-CSS/jax.js

Deep Learning Note: 5-3 语言模型

1. 语言建模

1.1. 语言模型

  考虑通过语音识别以下两个句子:

[code lang=”java”]The apple and pair salad.
The apple and pear salad.
[/code]

  这两个句子的读音完全一样,如果一个人听到这样的句子,可以很自然地认为听到了第二句,而对于算法来说,需要通过语言模型来判断当前输入的语音到底对应了那一句话。语言模型是语音识别和机器翻译系统的核心组件,其作用是,给定一个句子,给出该句子是特定一句话的概率,即给出:

P(y<1>,y<2>,,y<Ty>,)=3.2×1013

  这里语言模型给出输入语音是特定一句话的概率,假设模型给出:

P(Theappleandpairsalad)=3.2×1013P(Theappleandpearsalad)=5.7×1010

  算法通过比较上面两个概率,判断输入的语音是 The apple and pear salad.

1.2. 符号化

  要使用 RNN 构建语言模型,首先需要有大量的文本语料(Corpus)作为训练集。假设训练集中有这样一句话:

[code lang=”java”]Cats average 15 hours of sleep a day.
[/code]

  首先要对这句话进行符号化(Tokenize),即使用词汇表将这句话映射为一个向量。如果算法需要知道句子的结束位置,则在句子末尾追加一个额外的符号 <EOS>

[code lang=”java”]Cats average 15 hours of sleep a day.<EOS>
[/code]

  这样上面的句子就被映射为 [y<1>,y<2>,,y<9>] 这样一个向量,其中 y<9> 对应 <EOS>

  如果句子的某个单词在词汇表中找不到,则将其替换为一个特殊符号 <UNK>。例如对于下面的句子:

[code lang=”java”]The Egyptian Mau is a breed of cat.<EOS>
[/code]

  其中的 Mau 没有包含在词汇表中,则将该词替换为 <UNK>,句子变为:

[code lang=”java”]The Egyptian <UNK> is a breed of cat.<EOS>
[/code]

1.3. RNN 模型

  训练语言模型使用的 RNN 结构如图 1 所示。

图 1

图 1

  假设使用的训练样本为:

[code lang=”java”]Cats average 15 hours of sleep a day.<EOS>
[/code]

  此时有 Tx=Ty=9

  在 t=1 时刻,网络的输入 a<0>x<1> 都是一个零向量,此时网络通过 Softmax 输出句子第一个单词的概率。对于上面的句子,我们希望 P(cats) 具有最高概率,使得网络能够预测第一个单词为 cats

  在 t=2 时刻,网络的输入为上一步的激活值 a<1> 和句子中的第 1 个单词 y<1>。注意这里输入的 y<1> 是实际句子中的第一个单词 cats,而不是上一步中网络的预测 ˆy<1>。此时网络计算的是,给定句子中第一个词为 cats 时,句子第二个单词的概率,即 p(w|cats),其中 w 为词汇表中的各个单词。对于前述的句子,我们希望P(average|cats) 具有最高概率,使得网络能够预测第二个单词为 average

  以此类推,在 t=9 时刻,网络的输入为上一步的激活值 a<1> 和句子中的第 8 个单词 y<8>day),网络计算的是给定句子中前 8 个词,句子的第 9 个词的概率。对于前述的句子,我们希望 P(<EOS>|Catsaday) 具有最高概率,使得网络预测句子结束。

  训练网络时,定义单个样本在 t 时刻的损失函数如下:

L(ˆy<t>,y<t>)=iy<t>ilogˆy<t>i

  单个样本整体的损失函数为:

L=tL<t>(ˆy<t>,y<t>)

  对于由此训练得到的网络,给出句子开头的几个词,网络可以预测句子的下一个词是什么。对于一个句子 [y<1>,y<2>,y<3>],网络通过分别计算 P(y<1>)P(y<2>|y<1>)P(y<3>|y<1>,y<2>),得到整句话的概率 P(y<1>,y<2>,y<3>)=P(y<1>)P(y<2>|y<1>)P(y<3>|y<1>,y<2>)

2. 采样新的序列

  通过训练得到一个序列模型后,可以通过对其输出进行采样来大概地检查模型到底学到了什么。

  采样的步骤如图 2 所示。

图 2

图 2

  在 t=1 时刻,网络的输入 a<0>x<1> 都是一个零向量,和训练时类似,网络通过 Softmax 得到句子第一个单词的概率,包括所有可能出现在句子第一个位置上的词及其概率,在这些词中进行采样,选择一个词作为 ˆy<1>,假设选择了 the 这个词。

  在 t=2 时刻,网络的输入 a<1>ˆy<1>,注意这里输入的 ˆy<1> 是网络在上一个时刻的输出 the。此时通过网络可以得到当句子第一个词为 the 时,所有可能出现在句子第二个位置上的词及其概率,在这些词中采样,得到一个词作为 ˆy<2>

  以此类推,如果词汇表中包含表示句子结束的符号 <EOS>,则可以在网络输出 <EOS> 时结束,否则可以在采样的句子长度达到预先设定的上限(如 20 个词)时结束。如果词汇表中包含表示未知单词的符号 <UNK>,则网络也可能会输出这个符号,若不想在生成的句子中出现 <UNK>,则可以在采样得到 <UNK> 时再进行一次采样,直到得到非 <UNK> 的单词。

  通过以上步骤,就可以使用训练得到的 RNN 生成随机的句子。

  前面介绍的模型都是单词级的语言模型,使用的词汇表中包含很多单词,以单词为单位进行预测。根据需要,也可以构建字符级的语言模型,此时词汇表中包含所有字母,比如 26 个(大小写)英文字母、0 到 9 的数字以及空格、逗号、句号等标点符号。此时 y<t> 表示一个字符而不是一个单词。

  使用字符级模型的一个优势是不需要考虑有未知单词的情况,但它的一个主要缺点是序列的长度会变得很长,计算量很大。在捕获长距离的依赖,即学习句子前端的词对句子后端的词产生的影响上,字符级模型的性能不如单词级模型。

  目前自然语言处理的趋势是,大部分时候都会使用单词级的模型,随着计算能力的提升,也会使用字符级的模型来处理一些特定的问题,例如有很多未知单词的情况。