第一部分 · 预测下一个词

怎样生成句子,又怎样处理没见过的词?

模型可以一个词接一个词地写下去,但遇到训练中没见过的词或搭配时,就需要额外的处理。

一次抽取一个词,生成一句话 Lec 2 · Aug 27 · Lec 3 · Sep 1 回顾

二元模型的概率表不仅能给已有句子打分,也能用来生成新句子。我们从句首标记出发,按概率抽取第一个词,再根据这个词,决定接下来从哪一组概率中抽取。

这种做法叫采样(sampling):概率高的词更容易被抽中,但并不是每次都必须选概率最高的词。以餐馆查询语料得到的概率表为例,过程如下:

  1. 从 <s> 开始,按照词对 \((\text{<s>}, w)\) 的概率抽取首词。
  2. 选定这个词后,再按照词对 \((w, x)\) 的概率抽取后一个词。
  3. 继续重复,每次只把刚刚选出的词作为上下文,直到抽到 </s>。
  4. 把生成的词连起来,就是一句话。

一条可能的路径是 <s> I → I want → want to → to eat → eat Chinese → Chinese food → food </s>,得到 “I want to eat Chinese food”。可以自己拿一张概率表试着抽取几步;重新来一次,结果未必相同。

为什么生成结果越来越像莎士比亚? Lec 2 · Aug 27

课件用莎士比亚文本训练词组模型,再比较生成结果。随着 \(n\) 增大,文本越来越像原作:一元模型产生互不相连的词,二元模型开始出现局部短语,三元和四元模型有时能生成很像莎士比亚的句子。

但在认定模型已经学会写作之前,先看看它到底见过多少种可能的词语组合:

统计内容数值
词的总出现次数 \(N\)884,647
词表大小 \(V\)29,066
可能的相邻词对数 \(V^2\)≈ 8.44 亿
实际出现过的不同词对数300,000
从未出现的可能词对占比99.96%

即使文本里有接近 90 万次词语出现,绝大多数可能的词对仍然没有出现过。四个词的组合更稀少;课件也把四元词组称为 quadrigram。在这份有限的语料里,一个较长的上下文可能只有很少几种见过的后续,于是模型很容易接着复述原文。

所以课件说,生成结果像莎士比亚,是因为其中很多片段本来就来自莎士比亚。看起来写得好,可能主要是因为重复了熟悉的句子;绝大多数可能的词组,模型仍然没见过。

熟悉的文本预测得好,还不够 Lec 2 · Aug 27 · Lec 3 · Sep 1

如果把窗口加大就能生成像样的句子,为什么语言建模问题还没有解决,为什么还需要 GPT 这类模型?这里的困难是过拟合(overfitting):模型可能过分依赖训练材料里的具体表达。

  • 换一个领域,熟悉的规律就可能失效。莎士比亚文本与《华尔街日报》的词汇和用法差别很大,反过来也一样。课件用 “The WSJ is no Shakespeare” 提醒我们注意这种差异。固定词表还无法生成词表里没有的词。
  • 我们希望模型能够泛化(generalize)。也就是在新文本上仍能作出有用预测。在一份相似的测试集上表现好,与在我们关心的多种新场景里表现好,证据强度并不相同;这也不意味着任何模型都能保证适应任意测试集。
  • 缺失的计数会直接暴露这个问题。某个完全合理的词或短语,可能到测试时才第一次出现。

合理的表达,为什么会被算成零概率? Lec 2 · Aug 27 · Lec 3 · Sep 1

见过“denied the”,却没见过这次的后续

训练文本:… denied the allegations / … denied the reports / … denied the claims / … denied the request。
测试文本:… denied the offer / … denied the loan。

如果直接使用原始计数,\(P(\text{offer} \mid \text{denied the}) = 0\)。把这个因子与其他概率相乘,整段测试文本的概率就变成零。困惑度也因此没有有限值:概率的倒数趋于无穷大。

第 3 讲把零计数分成两种情况:

  1. 连词本身都没见过。这个词的一元计数为零,也不在训练词表里,称为词表外词(out-of-vocabulary,OOV)。新术语、人名、方言形式,以及语言的变化都会造成这种情况。这里所说的词次(token),指词在文本中的一次具体出现。
  2. 词都认识,但组合没见过。单个词在训练中出现过,它们组成的相邻词对或更长词组却从未出现。

还要区分两种计算结果:如果上下文出现过,只有这次的后续没出现过,原始估计就是零;如果连上下文本身都没出现过,计数比值的分母就是零,概率没有定义。无论哪一种,都需要处理后才能给新文本分配有用的概率。

课程介绍了两种配合使用的办法:用 <UNK> 代表未知词,用平滑给没见过的组合分配概率。

先为未知词准备一个共同的位置

<UNK> 是表示“未知词”的特殊符号。不要等到测试时才临时加入它,而应当在训练中就准备一些相应的例子:

  • 选择一个较小的次数门槛 \(n\)。把训练文本中出现次数低于门槛的词统一替换成 <UNK>,然后重新计数、估计概率。
  • 测试时,遇到不在保留词表里的词,就把它映射为 <UNK>。
  • 比较模型时要小心。如果词表取得很小,大量不同词都会落入同一个 <UNK> 类别,困惑度可能人为下降。此时预测任务变简单了,并不表示模型更擅长区分真实的词。

这样做可以给“未知词”这一类分配概率,但无法恢复每个新词的具体身份。涉及 <UNK> 的组合,也可能仍然需要平滑。

词表之外的词,模型准备怎样处理?

封闭词表(closed vocabulary)开放词表(open vocabulary)
预先选定一个词表,例如来自词典,并假设需要建模的词都在其中。真实文本里的新人名、拼写错误和方言形式,可能打破这个假设,因此需要额外的处理规则。允许遇到训练时没有见过的词。按整词建模时,可以把它们映射为 <UNK>;现代模型常用子词切分,把新词拆成已知的小片段。即使片段集合固定,能够处理的完整词也不必限定在一份预先列出的词表里。
本页要记住什么
  • 生成文本,就是反复按条件概率抽取下一个词,直到抽到 </s>。
  • 长上下文可能让模型复现训练片段,从而生成很像样的句子;仅凭这一点,还不能证明它能预测好新文本。
  • 某一步的概率为零,就会让困惑度变成无穷大。未知词用 <UNK> 表示,未见组合用平滑处理。