一次抽取一个词,生成一句话 Lec 2 · Aug 27 · Lec 3 · Sep 1 回顾
二元模型的概率表不仅能给已有句子打分,也能用来生成新句子。我们从句首标记出发,按概率抽取第一个词,再根据这个词,决定接下来从哪一组概率中抽取。
这种做法叫采样(sampling):概率高的词更容易被抽中,但并不是每次都必须选概率最高的词。以餐馆查询语料得到的概率表为例,过程如下:
- 从
<s>开始,按照词对 \((\text{<s>}, w)\) 的概率抽取首词。 - 选定这个词后,再按照词对 \((w, x)\) 的概率抽取后一个词。
- 继续重复,每次只把刚刚选出的词作为上下文,直到抽到
</s>。 - 把生成的词连起来,就是一句话。
一条可能的路径是 <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 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 讲把零计数分成两种情况:
- 连词本身都没见过。这个词的一元计数为零,也不在训练词表里,称为词表外词(out-of-vocabulary,OOV)。新术语、人名、方言形式,以及语言的变化都会造成这种情况。这里所说的词次(token),指词在文本中的一次具体出现。
- 词都认识,但组合没见过。单个词在训练中出现过,它们组成的相邻词对或更长词组却从未出现。
还要区分两种计算结果:如果上下文出现过,只有这次的后续没出现过,原始估计就是零;如果连上下文本身都没出现过,计数比值的分母就是零,概率没有定义。无论哪一种,都需要处理后才能给新文本分配有用的概率。
课程介绍了两种配合使用的办法:用 <UNK> 代表未知词,用平滑给没见过的组合分配概率。
先为未知词准备一个共同的位置
<UNK> 是表示“未知词”的特殊符号。不要等到测试时才临时加入它,而应当在训练中就准备一些相应的例子:
- 选择一个较小的次数门槛 \(n\)。把训练文本中出现次数低于门槛的词统一替换成
<UNK>,然后重新计数、估计概率。 - 测试时,遇到不在保留词表里的词,就把它映射为
<UNK>。 - 比较模型时要小心。如果词表取得很小,大量不同词都会落入同一个
<UNK>类别,困惑度可能人为下降。此时预测任务变简单了,并不表示模型更擅长区分真实的词。
这样做可以给“未知词”这一类分配概率,但无法恢复每个新词的具体身份。涉及 <UNK> 的组合,也可能仍然需要平滑。
词表之外的词,模型准备怎样处理?
| 封闭词表(closed vocabulary) | 开放词表(open vocabulary) |
|---|---|
| 预先选定一个词表,例如来自词典,并假设需要建模的词都在其中。真实文本里的新人名、拼写错误和方言形式,可能打破这个假设,因此需要额外的处理规则。 | 允许遇到训练时没有见过的词。按整词建模时,可以把它们映射为 <UNK>;现代模型常用子词切分,把新词拆成已知的小片段。即使片段集合固定,能够处理的完整词也不必限定在一份预先列出的词表里。 |
- 生成文本,就是反复按条件概率抽取下一个词,直到抽到
</s>。 - 长上下文可能让模型复现训练片段,从而生成很像样的句子;仅凭这一点,还不能证明它能预测好新文本。
- 某一步的概率为零,就会让困惑度变成无穷大。未知词用
<UNK>表示,未见组合用平滑处理。