语言模型的任务从古到今只有一句话:给序列 $w_1,\dots,w_T$ 算概率。链式法则把它拆成条件概率的连乘,
$$ p(w_1,\dots,w_T)=\prod_{t=1}^{T}p(w_t\mid w_1,\dots,w_{t-1}), $$
难的是每一项的右边有指数多个前缀。n-gram 和神经语言模型对这个难题给出了两代截然不同的解法,分歧点不在技巧,而在概率存在哪里:一个存在计数表里,一个存在参数里。
n-gram:把概率存成一张表
$n$-gram 模型做马尔可夫假设:只看最近 $n-1$ 个词。条件概率直接用频率估计,
$$ p(w_t\mid w_{t-n+1:t-1})=\frac{C(w_{t-n+1:t})}{C(w_{t-n+1:t-1})}, $$
分子是前缀加当前词的共现计数,分母是前缀计数。三元的表需要 $|V|^3$ 个格子,英语里能数到的只是冰山一角。这套方法 1980 年代就成熟了,CMU 的 SRILM 工具链到现在还在用,它的问题是结构性的。
计数为零不等于概率为零。 语料里没出现过的三元组,频率估计是 0,但把它们全部判死刑的模型没法用。平滑(smoothing)就是给 unseen 事件重新分配质量。最简单的 add-$k$ 平滑把每个计数加 $k$ 再归一化:
$$ p_{\text{add-}k}(w\mid h)=\frac{C(hw)+k}{C(h)+k|V|}. $$
$k$ 是凭空注入的伪计数,它把见过的分布整体压低,给所有未见事件均分一小份质量。更精细的 Kneser-Ney 平滑用低阶模型的插值来分配这部分质量,并刻意给"出现在更多不同上下文中的词"更高的回退概率——这是计数派的最后一座高峰。
平滑的困境:表没有泛化能力
加平滑可以让困惑度好看几个点,但救不了根本问题。看一个例子:语料里见过"猫 在 沙发 上",没见过"狗 在 沙发 上"。对 n-gram 而言这两个序列毫不相干,"猫"和"狗"只是两个离散的表索引,平滑只能给"狗在沙发上"一个平均的、无差别的概率,不会因为"狗"和"猫"处境相似而多分一点。
形式化一点:$n$-gram 的每一个前缀是一个独立的表行,行数随 $|V|^{n-1}$ 爆炸,行与行之间没有任何参数共享。想要"语义相近的词共享统计",就需要一个词之间的距离概念,而离散索引之间连距离都没有定义。这不是平滑技术不够聪明,是表示形式不允许。
Bengio 2003:把词放进向量空间
神经概率语言模型(Bengio et al., 2003, JMLR)的改动只有一处,但改在了根上:每个词 $w$ 对应一个可学习的向量 $e(w)\in\mathbb{R}^d$,条件概率由神经网络算出,
$$ x=\big[e(w_{t-n+1});\dots;e(w_{t-1})\big],\qquad h=\tanh(Wx+b),\qquad p=\mathrm{softmax}(Vh+c). $$
概率不再来自计数表,而是来自两组参数:嵌入矩阵 $E\in\mathbb{R}^{|V|\times d}$ 和输出矩阵 $V$。softmax 的每一列 $v_w$ 可以读作输出侧的词向量,词 $w$ 在前缀 $h$ 下的 logits 就是 $v_w^\top h$——打分即相似度。这给了"猫/狗"共享统计的通道:如果训练数据里"猫"和"狗"出现在相似上下文,它们的嵌入会被同样的梯度拉向相近方向。
参数共享体现在两处。前向看,所有前缀共用同一组 $W,V$——"the cat sat"和"the dog ran"走同一条计算图,只是喂进去的向量不同。反向看,梯度 $\partial \mathcal{L}/\partial e(w)$ 把每次出现的信息都累积回 $E$ 的对应行,一个词从成千上万次出现中累计的统计量,压缩进 $d$ 维(原文用 50 到 100 维)的向量。表是每行一个独立桶,向量是让所有行互相借钱——这就是"分布式表示"这个名字的本义:一个词的统计特征分布地存在于所有维上。
为什么这能解决稀疏
回到"狗 在 沙发上"。没见过这个三元组,但见过大量 $X$ 在沙发上的上下文,其中若干个 $X$ 的嵌入与"狗"相近。softmax 的打分 $v_{\text{狗}}^\top h$ 里,$h$ 由前缀嵌入算出,与"猫在沙发上"算出的 $h$ 高度相关;如果训练中"狗"和"猫"的输出向量也被拉得接近(它们可以互换出现在许多相同上下文里),那么"狗"在这个前缀下自动得到与"猫"相近的概率。没有见过的事件,可以通过表示空间里的邻居插值出来。 n-gram 的插值靠人工设计的回退公式,神经模型的插值是学出来的,而且不只插值一个词——是整个连续空间里所有方向上的插值。
更妙的是模型容量与词表解耦了:n-gram 的表规模是 $|V|^n$,神经模型的参数是 $|V|d + (n-1)d\cdot h + h|V|$,对词表大小只线性依赖。这省下的不只是内存,是把"词与词的关系"这个指数级的对象压成了 $d\times d$ 的双线性结构。
一次小小的数值对照
用同一个微型语料分别训 add-1 平滑的 bigram 和一个两层的 Bengio 式模型,最直观的差别在未见事件上:bigram 给所有未见续词均分回退质量,而神经模型给"狗 在 沙发 上"的概率接近它给"猫 在 沙发 上"的概率,差距取决于嵌入空间里猫狗两向量的距离。这个距离不是先验编码的,是训练数据里"猫/狗"大量可互换的共现自己学出来的。
历史的后续
表示学习的胜利比想象彻底。Bengio 模型里 softmax 的权重矩阵 $V$ 按今天的标准就是输出嵌入,word2vec(2013)证明了把它单独拿来做对比学习就足以得到高质量的词向量;而 Transformer(2017)把固定窗口的前缀换成全局注意力之后,"分布式表示解决稀疏"这条逻辑原封不动地搬了上去——每个 token 的表示同样由全部上下文共享参数算出。从计数表到向量空间,换来的是泛化;从固定窗口到注意力,换来的是上下文的完整使用。GPT 系列把这两步都走完了,剩下的就是堆数据和算力,那是 Chinchilla 与 scaling law 章节的故事。
n-gram 也不是一无是处:它的计数是精确的、可解释的、增量可更新的,现代系统里仍作为 baseline 和特征存在(检索里的 BM25 就是加了词频饱和与长度归一的 bigram/unigram 统计)。理解它的极限,才知道神经网络把哪件事做成了——把"相似"这个模糊概念变成了可计算的参数几何。